Зачем тебе делать весь класс запечатанным / финальным? - PullRequest
9 голосов
/ 31 января 2010

Я понимаю мотивацию создания отдельных методов класса sealed / final, но какой цели служит полное запрещение наследования от класса?Хотя переопределение определенных методов может привести к плохим вещам, я не понимаю, как разрешение наследования от вашего класса просто добавить поведение к нему без переопределения существующего поведения может быть плохим.Если вы действительно хотите запретить переопределение чего-либо в своем классе, почему бы не сделать каждый метод окончательным, но все же разрешить наследование для добавления поведения?

Ответы [ 6 ]

4 голосов
/ 31 января 2010

Есть несколько хороших обсуждений по этому вопросу в вопросе «Почему строка является конечной в Java»: Почему класс String объявлен окончательным в Java?

Основная сводка в этом случае: String является неизменной, и, если она может быть разделена на подклассы, подкласс может сделать ее изменчивой.

3 голосов
/ 31 января 2010

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

3 голосов
/ 31 января 2010

В целом, класс можно сделать окончательным, чтобы сохранить инварианты, которые заставляют его работать. Я очень рекомендую «Эффективную Java» Джошуа Блоха для отличного обсуждения этого и смежных вопросов.

2 голосов
/ 31 января 2010

Подумайте об этом следующим образом: вы провели последние 3 месяца, работая над базовым классом для своей собственной платформы, которую будут использовать другие, и вся согласованность структуры основана на коде, написанном в этом классе, модифицируя это Класс может вызвать ошибки, ошибки и неправильное поведение вашей платформы, как вы препятствуете его замечательным программистам расширять его и переопределять один из его методов?

В дополнение к этому есть класс, который должен быть неизменным, такой как класс java.lang.String в Java, расширение его и изменение его поведения может привести к большим беспорядкам!

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

0 голосов
/ 17 февраля 2014

Насколько я знаю, речь идет о создании инвариантов.

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

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

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

Скажем, у вас есть коллекция классов CC1, которая объединяется с какой-то целью, и один из этих классов CC1_A должен "производить" только неизменяемые объекты (или любой другой инвариант, который вы хотите). Затем вы продолжаете и расширяете CC1_A, делая CC2_AX (расширенный A в коллекции второго класса). Теперь вы можете использовать материал CC1, передавая CC2_AX, где требуется CC1_A. Тем не менее, CC1 был построен, предполагая, что объекты CC1_A являются неизменяемыми, а ваши объекты CC2_AX - нет (предположим, они не только для примера). Это может привести к серьезным проблемам в вашей программе. Такая проблема может возникнуть даже внутри класса. Например, методы CC1_A, вероятно, будут предполагать, что объекты CC1_A являются неизменяемыми, поэтому методы CC2_AX, полученные из CC1_A, могут потенциально завершиться сбоем, поскольку CC2_AX нарушает свойство неизменяемости.

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

Кстати, некоторые другие инварианты включают в себя такие вещи, как:

  • Метод сортировки должен быть стабильным.
  • В методе используется <другой такой> алгоритм.
  • Эта реализация списка должна использовать реализацию простого связанного списка, как описано .

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

0 голосов
/ 31 января 2010

Я думаю, это зависит.

Если у меня есть внутреннее приложение, я бы не использовал финал на уровне класса по умолчанию. Код просто становится слишком загроможденным. В некоторых случаях финальный модификатор даже очень раздражает, если я хочу безопасно провести рефакторинг (см. программирование по разнице термин). В некоторых случаях «default-final-mania» создавала большие проблемы, когда я пытался провести рефакторинг.

С другой стороны, если я спроектирую api / framework, в котором код больше зависит от расширения, я бы использовал final для классов «более агрессивно». В этом случае неправильное расширение может быть большой проблемой, а модификатор 'final' является безопасным способом избежать таких ошибок программирования.

Но я просто против того, чтобы по умолчанию использовать 'final', как это делают многие. У этого часто есть больше недостатков как преимущества. Для меня значения по умолчанию должны быть «разумными и более распространенными».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...