Хорошо, как и многие другие люди ...
Да, я думаю, что вполне разумно рекомендовать закрывать классы по умолчанию.
Это соответствует рекомендации Джоша Блоха в его превосходной книге Effective Java, 2-е издание :
Создай наследство или запрети его.
Проектирование для наследования является сложным и может сделать вашу реализацию менее гибкой, особенно если у вас есть виртуальные методы, один из которых вызывает другой. Может быть, они перегружены, а может и нет. Тот факт, что один вызывает другой , должен быть задокументирован , иначе вы не сможете безопасно переопределить ни один метод - вы не знаете, когда он будет вызван, или безопасно ли вызывать другой метод без риск переполнения стека.
Теперь, если вы позже захотите изменить, какие вызовы методов, какие в более поздней версии, вы не сможете - вы потенциально сломаете подклассы. Таким образом, во имя «гибкости» вы фактически сделали реализацию менее гибкой, и вам пришлось более подробно документировать детали реализации. Для меня это не очень хорошая идея.
Далее следует неизменность - мне нравятся неизменные типы. Я считаю, что их легче рассуждать, чем изменяемые типы. Это одна из причин, почему API Joda Time лучше, чем использование Date
и Calendar
в Java. Но открытый класс никогда не может быть известным как 1032 * неизменным. Если я принимаю параметр типа Foo
, я могу полагаться на свойства , объявленные в Foo
, которые не могут быть изменены с течением времени, но я не могу полагаться на то, что сам объект не будет изменено - в подклассе может быть изменяемое свойство. Небеса, помогите мне, если это свойство также используется переопределением некоторого виртуального метода. Волна прощается со многими преимуществами неизменности. (По иронии судьбы, Joda Time имеет очень большие иерархии наследования - часто с такими вещами, как «подклассы должны быть неизменными. Большая иерархия наследования Chronology
затруднила понимание при портировании на C #.)
Наконец, есть аспект чрезмерного использования наследования. Лично я предпочитаю композицию, а не наследование, где это возможно. Я люблю полиморфизм интерфейсов, и иногда Я использую наследование реализации - но это редко подходит для моего опыта. Запечатывание классов позволяет избежать того, что они неуместно получены из того места, где состав лучше подходит.
РЕДАКТИРОВАТЬ: Я также хотел бы указать читателям на сообщение в блоге Эрика Липперта от 2004 года о том, почему так много классов платформы запечатаны. Есть много мест, где я бы хотел, чтобы .NET предоставил интерфейс , с которым мы могли бы работать для тестируемости, но это немного другой запрос ...