Открыто закрытый принцип и модификатор “финала” Java

21
задан rmaruszewski 18 March 2009 в 12:08
поделиться

7 ответов

Откровенно я думаю, что открываться/закрывать принцип является больше анахронизмом, чем нет. Это семы с 80-х и 90-х, когда платформы OO были основаны на принципе, что все должно наследоваться чему-то еще и что все должно быть подподдающимся классификации.

Это больше всего характеризовалось в платформах UI эры как MFC и Java Swing. В Swing у Вас есть смешное наследование, где (iirc) кнопка расширяет флажок (или наоборот) предоставление одного из них поведение, которое не используется (я думаю, что это, это - setDisabled () запрос к флажку). Почему они совместно используют родословную? Никакая причина кроме, ну, в общем, у них были некоторые общие методы.

В эти дни состав одобрен по наследованию. Принимая во внимание, что Java позволил наследование по умолчанию, .NET проявил (более современный) подход запрещения его по умолчанию, который я думаю, более корректно (и более согласовывается с принципами Josh Bloch).

DI/МОК также далее изложили доводы для состава.

Josh Bloch также указывает, что инкапсуляция повреждений наследования и дает некоторые хорошие примеры почему. Было также продемонстрировано, что изменение поведения наборов Java более последовательно, если сделано делегацией вместо того, чтобы расширить классы.

Лично я в основном просматриваю наследование как немного больше, чем деталь реализации в эти дни.

26
ответ дан cletus 29 November 2019 в 04:04
поделиться

Я не думаю, что эти два оператора противоречат друг другу. Тип может быть открыт для расширения и все еще быть закрыт для наследования.

Один способ сделать это должно использовать внедрение зависимости. Вместо того, чтобы создать экземпляры его собственных типов помощника, типу можно было предоставить их после создания. Это позволяет Вам изменять части (т.е. открытый для расширения) типа, не изменяя сам тип (т.е. близко для модификации).

8
ответ дан Brian Rasmussen 29 November 2019 в 04:04
поделиться

В открыто закрытый принцип (открываются для расширения, закрытого для модификации) можно все еще использовать заключительный модификатор. Вот один пример:

public final class ClosedClass {

    private IMyExtension myExtension;

    public ClosedClass(IMyExtension myExtension)
    {
        this.myExtension = myExtension;
    }

    // methods that use the IMyExtension object

}

public interface IMyExtension {
    public void doStuff();
}

Эти ClosedClass закрывается для модификации в классе, но открытый для расширения через другой. В этом случае это может иметь что-либо, что реализует эти IMyExtension интерфейс. Этот прием является изменением внедрения зависимости, так как мы подаем закрытый класс с другим, в этом случае через конструктора. Так как расширение interface, это не может быть final, но его класс с реализацией может быть.

Используя финал на классах для закрытия их в Java подобно использованию sealed в C#. Существуют подобные обсуждения об этом на стороне.NET.

7
ответ дан Community 29 November 2019 в 04:04
поделиться

В наше время я использую заключительный модификатор по умолчанию, почти рефлексивно как часть шаблона. Это делает вещи легче рассуждать о, когда Вы знаете, что данный метод будет всегда функционировать, как замечено в коде, на который Вы смотрите прямо сейчас.

, Конечно, иногда существуют ситуации, где иерархия классов точно, что Вы хотите, и было бы глупо не использовать то тогда. Но бойтесь иерархий больше чем двух уровней или, где неабстрактные классы далее разделяются на подклассы. Класс должен быть или кратким обзором или финалом.

Большую часть времени, с помощью состава способ пойти. Поместите все общее оборудование в один класс, поместите различные случаи в различные классы, затем составные экземпляры, чтобы иметь целую работу.

можно назвать это "внедрение зависимости", или "стратегическую модель" или "шаблон"посетитель"" или что бы то ни было, но к чему это сводится, использует состав вместо наследования для предотвращения повторения.

5
ответ дан Zarkonnen 29 November 2019 в 04:04
поделиться

Я уважаю Joshua Bloch много, и я полагаю Эффективный Java в значительной степени быть Java библия . Но я думаю, что, автоматически принимая значение по умолчанию к private доступ часто является ошибкой. Я склонен делать вещи protected по умолчанию так, чтобы к ним можно было, по крайней мере, получить доступ путем расширения класса. Это главным образом выросло из потребности до компонентов модульного теста, но я также нахожу это удобным для переопределения поведения по умолчанию классов. Я нахожу это очень раздражающим, когда я работаю в кодовой базе своей собственной компании и заканчиваю тем, что имел необходимость скопировать & измените источник, потому что автор принял решение "скрыть" все. Если это находится вообще в моем питании, я лоббирую, чтобы изменить доступ на protected для предотвращения дублирования, которое намного хуже, по моему скромному мнению.

Также имеют в виду, что образование Bloch находится в разработке очень общественность основополагающие библиотеки API; панель для получения такого "корректного" кода должна быть установлена очень высоко, таким образом, возможности, это не действительно та же ситуация как большая часть кода, который Вы будете писать. Важные библиотеки, такие как сам JRE склонны быть более строгими, чтобы удостовериться, что языком не злоупотребляют. Посмотрите весь , удержал от использования API в JRE? Почти невозможно изменить или удалить их. Ваша кодовая база, вероятно, не установлена в камне, таким образом, Вы делаете , имеют возможность починить вещи, если оказывается, что Вы сделали ошибку первоначально.

4
ответ дан Limbic System 29 November 2019 в 04:04
поделиться

Эти два оператора

объекты программного обеспечения (классы, модули, функции, и т.д.) должны быть открыты для расширения, но закрытые для модификации.

и

Дизайн и документ для наследования, или иначе запрещают его.

не находятся в прямом противоречии друг с другом. Можно следовать за открыто закрытым принципом, пока Вы разрабатываете и документ для него (согласно совету Bloch).

я не думаю, что Bloch заявляет, что Вы должны предпочитать запрещать наследование при помощи заключительного модификатора, просто что необходимо явно принять решение позволить или запретить наследование в каждом классе, который Вы создаете. Его совет состоит в том, что необходимо думать об этом и решить для себя, вместо того, чтобы просто принять поведение по умолчанию компилятора.

3
ответ дан Bill the Lizard 29 November 2019 в 04:04
поделиться

Я не думаю, что принцип открытого / закрытого состояния, представленный изначально, позволяет интерпретировать, что конечные классы могут быть расширен путем внедрения зависимостей.

Насколько я понимаю, принцип заключается в том, чтобы не разрешать прямые изменения кода, который был запущен в производство, и способ добиться этого, при этом разрешая модификации функциональности, заключается в использовании наследования реализации.

Как указано в первом ответе, это имеет исторические корни. Десятилетия назад наследование было в пользу, тестирование разработчиками было неслыханным делом, а перекомпиляция кодовой базы часто занимала слишком много времени.

Кроме того, Учтите, что в C ++ детали реализации класса (в частности, частные поля) обычно представлялись в файле заголовка «.h», поэтому, если программисту нужно его изменить, всем клиентам потребуется перекомпиляция. Обратите внимание, что это не относится к современным языкам, таким как Java или C #. Кроме того, я не думаю, что тогда разработчики могли рассчитывать на сложные IDE, способные выполнять анализ зависимостей «на лету», избегая необходимости частой полной перестройки.

По моему собственному опыту, я предпочитаю делать прямо противоположное: «классы должны быть закрыты для расширения ( final ) по умолчанию, но открыты для изменения». Подумайте об этом: сегодня мы отдаем предпочтение таким методам, как контроль версий (упрощает восстановление / сравнение предыдущих версий класса),

1
ответ дан 29 November 2019 в 04:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: