final по дефолту

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Встретилась мне любопытная статья - автор предлагает делать все классы final, кроме тех редких случаев, когда класс явно предназначен для наследования.
В первом приближении мне эта идея нравится.

https://matthiasnoback.nl/2018/09/final-classes-by-default-why/
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
я как-то пропустил тот тред
кроме того, мир меняется, замокать налету сейчас не проблема
 

Вурдалак

Продвинутый новичок
Раньше замокать final можно было только через какой-то хак: подмена автолоадера или низкоуровневая фигня для тестов типа uopz — оба решения не подходят для production. Что-то изменилось с тех пор?
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
1. мокать нужно для stage/ci, для прода мокать не нужно вообще

2. почему мокать надо именно наследованием? мок должен подменить класс, соответственно, можно распарсить код класса и создать мок - кажется, в баду сделали такую либу
 

Вурдалак

Продвинутый новичок
мокать нужно для stage/ci, для прода мокать не нужно вообще
Под «мокать» я там и тут понимаю кое-что более общее: например, генерация proxy (как это делает Doctrine для entity) для lazy loading и прочих штук. Поэтому классы Doctrine приходится оставлять открытыми для наследования: чисто инфраструктурная проблема.
 

AnrDaemon

Продвинутый новичок
Встретилась мне любопытная статья - автор предлагает делать все классы final, кроме тех редких случаев, когда класс явно предназначен для наследования.
В первом приближении мне эта идея нравится.

https://matthiasnoback.nl/2018/09/final-classes-by-default-why/
Очередной религиозный холивар.

All generalizations are false, including this one.
-- Mark Twain
 

Вурдалак

Продвинутый новичок
Добавлю, то в Kotlin (позиционируемый как более современная Java) всё наоборот: там есть ключевое слово open для тех классов, которые хочется оставить открытыми для наследования; а final там по умолчанию. Поэтому каждый раз, когда видите отсутствие final у неабстрактного класса, задавайте вопрос: «а почему этот класс открыли для наследования?».

https://kotlinlang.org/docs/reference/classes.html
 

AnrDaemon

Продвинутый новичок
Я могу сидеть и придумывать аргументы в пользу обоих подходов.
Но не буду. Ибо…
1. У меня болит голова от бессмысленных споров.
2. У меня болит голова от рабочих вопросов.
3. У меня тупо болит голова. Дождь был слишком короткий.

Если кому-то хочется портить себе карму наследованием от моих классов - ради Б-га, это НЕ МОЁ ДЕЛО.
Если я знаю, что поведение класса сломается, если конкретный метод заменить, я объявлю этот метод final.
final __toString() самое частое в моей практике на сегодня. Ибо.
 

Вурдалак

Продвинутый новичок
2. почему мокать надо именно наследованием? мок должен подменить класс, соответственно, можно распарсить код класса и создать мок - кажется, в баду сделали такую либу
В баду тупо сделали аналог подмены с автолоадером, о котором я говорил: это не подходит для production.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Очередной религиозный холивар.

All generalizations are false, including this one.
-- Mark Twain
Правильно подмечено. Уточняю. Классы фреймворков, библиотек, драйверов, служебные штуки я в этой теме предпочел бы не рассматривать. В первую очередь, речь о userland-коде.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
@AnrDaemon, если тебе не хочется участвовать в обсуждении - не обсуждай свое желание, просто сделай это :)

с наследованием у меня есть одна простая проблема: после того, как я уволил разработчика, его код мне надо поддерживать
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
В баду тупо сделали аналог подмены с автолоадером, о котором я говорил: это не подходит для production.
если речь о proxy - здесь будет уместна аггрегация, рефакторинг, объявление интерфейса
а в случае lazy load - это класс, который явно создается с возможножностью наследования

а для тестов подмена на автолоаде - то, что надо
 

Вурдалак

Продвинутый новичок
если речь о proxy - здесь будет уместна аггрегация - рефакторинг, создание интерфейса
а в случае lazy load - это класс, который явно создается с возможножностью наследования
В том-то и дело, что с точки зрения архитектуры тебе нахер не нужен интерфейс User: реализация модели одна и больше быть не может. Проксирование тут чисто инфраструктурная штука, контекст модели от этого по-хорошему страдать не должен (модель не должна зависеть от причуд ORM в идеальном случае).
 

Adelf

Administrator
Команда форума
Давно уже обсуждали, что ORM - это вынужденный хак.
Персистент - это вынужденный хак.
База данных -вынужденный хак. и т.д.

Я не помню ни одного класса у меня, который не абстрактный и от которого хотелось бы наследовать. И котлиновская идея с open мне очень нравится.

И да. Идею эту с Вурдалаковской подачи тоже обсуждали давным давно.
 

Adelf

Administrator
Команда форума
Я могу сидеть и придумывать аргументы в пользу обоих подходов.
Но не буду. Ибо…
1. У меня болит голова от бессмысленных споров.
2. У меня болит голова от рабочих вопросов.
3. У меня тупо болит голова. Дождь был слишком короткий.
Эти аргументы с женой будешь обсуждать. Давай на форуме по существу.

Если кому-то хочется портить себе карму наследованием от моих классов - ради Б-га, это НЕ МОЁ ДЕЛО.
Ты никогда не работал с команде?

Если я знаю, что поведение класса сломается, если конкретный метод заменить, я объявлю этот метод final.
final __toString() самое частое в моей практике на сегодня. Ибо.
Спрогнозировать такое сложно. Поэтому final на весь класс и спишь спокойно.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
В том-то и дело, что с точки зрения архитектуры тебе нахер не нужен интерфейс User: реализация модели одна и больше быть не может. Проксирование тут чисто инфраструктурная штука, контекст модели от этого по-хорошему страдать не должен (модель не должна зависеть от причуд ORM в идеальном случае).
определение интерфейса для сущности и proxy - это канонический подход из описания паттерна и синтаксиса php для интерфесов
https://ru.wikipedia.org/wiki/Заместитель_(шаблон_проектирования)#Решение
https://en.wikipedia.org/wiki/Proxy_pattern#Java
 
Последнее редактирование:

Вурдалак

Продвинутый новичок
определение интерфейса для сущности и proxy - это канонический подход из описания паттерна и синтаксиса php для интерфесов
https://ru.wikipedia.org/wiki/Заместитель_(шаблон_проектирования)#Решение
Ты не понял о чём я веду речь: модели насрать на твой паттерн из книжки 1995 года.
Здесь мы видим техническую необходимость в наследовании.
Если бы язык был спроектирован немного по-другому, этого можно было бы избежать.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
конечно, с duck typing в golang/typescript все проще, но в java тут подразумевается определение интерфейса(добавил ссылку), а php унаследовал ее объектную модель
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
технической необходимости наследования в случае с proxy не то что нет, а не должно быть по определению

а вот с lazy load - конечно, для этого наследование и создано
 
Сверху