Подтвердить что ты не робот

Должен ли я рекомендовать классы уплотнения по умолчанию?

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

Я нахожу это странным, что в java и С# классифицируются непечатаемые/не окончательные значения pr по умолчанию. Я думаю, что создание классов, закрытых, значительно улучшает читаемость кода.

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

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

4b9b3361

Ответ 1

Хорошо, так как многие другие люди весили...

Да, я думаю, что вполне разумно рекомендовать, чтобы по умолчанию были закрыты классы.

Это согласуется с рекомендацией Джоша Блоха в его отличной книге Эффективная Java, 2-е издание:

Создайте для наследования или запретите его.

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

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

Далее - неизменность - мне нравятся неизменные типы. Мне легче их рассуждать, чем изменяться. Это одна из причин, по которым API Joda Time лучше, чем использование Date и Calendar в Java. Но неизвестный класс никогда не может быть известен как неизменный. Если я принимаю параметр типа Foo, я могу полагаться на свойства, объявленные в Foo, не меняться со временем, но я не могу полагаться на сам объект, который не изменяется - может быть изменяемое свойство в подклассе. Небеса помогают мне, если это свойство также используется переопределением какого-либо виртуального метода. Прощайтесь со многими из преимуществ неизменности. (Как ни странно, Joda Time имеет очень большие иерархии наследования - часто с вещами, говорящими: "Подклассы должны быть неизменными. Большая иерархия наследования Chronology затрудняла понимание при переносе на С#.)

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

EDIT: Я также хотел бы указать читателям на запись в блоге Эрика Липперта с 2004 г. о том, почему так много классов каркаса закрыты. Есть много мест, где мне хотелось бы, чтобы .NET обеспечивал интерфейс, над которым мы могли бы работать, для проверки, но это немного другой запрос...

Ответ 2

Я считаю, что решения архитектурного дизайна сделаны для общения с другими разработчиками (в том числе с будущими разработчиками обслуживания), что-то важное.

Уплотняющие классы сообщают, что реализация не должна быть переопределена. Он сообщает, что класс не должен выдаваться. Есть серьезные основания для печати. ​​

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

Но как бы вы общались с другими разработчиками, что класс не должен наследоваться из-за чего-то? Вы действительно не можете. Вы застряли.

Кроме того, уплотнение класса не улучшает читаемость. Я просто этого не вижу. Если наследование является проблемой при разработке ООП, то у нас есть гораздо большая проблема.

Ответ 3

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

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

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

Ответ 4

Честно говоря, я считаю, что классы, которые не были запечатаны по умолчанию в С#, выглядят странно и неуместно с тем, как остальные по умолчанию работают на языке.

По умолчанию классы internal. По умолчанию поля private. По умолчанию члены private.

По-видимому, существует тенденция, которая по умолчанию указывает на наименее правдоподобный доступ. Было бы разумно, что ключевое слово unsealed должно выйти в С# вместо sealed.

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

Ответ 5

В наследовании от класса не должно быть ничего плохого.

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

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

Тогда у вас будет 2 реализации одной и той же вещи, одна, вероятно, хуже, чем другая, и 2 части кода для поддержки.

Лучше просто держать его незапечатанным. Никакой вред в нем не распечатывается.

Ответ 6

© Джеффри Рихтер

Есть три причины, почему класс лучше, чем незапечатанный класс:

  • Версии. Когда класс изначально запечатан, он может измениться на распечатывается в будущем без нарушение совместимость. Однако однажды класс вскрыт, вы никогда не сможете измените его на печать в будущем, как это сломает все производные классы. Кроме того, если непечатанный класс определяет любые незапечатанные виртуальные методы, упорядочение вызовов виртуального метода необходимо поддерживать с новыми версиями или существует вероятность нарушения в будущем.
  • Производительность. Как обсуждалось в предыдущем разделе, вызов виртуального метод не выполняет, а также вызов невиртуального метода, потому что CLR должен искать тип объекта во время выполнения, чтобы определить, какой тип определяет метод для вызова. Однако, если JIT компилятор видит вызов виртуального метод с использованием герметичного типа, JIT компилятор может создавать более эффективные кода путем вызова метода nonvirtually. Он может это сделать, потому что он знает, что, возможно, не может быть если класс закрыт.
  • Безопасность: и предсказуемость Класс должен защищать свое собственное состояние, а не позволяют себе когда-либо стать коррумпированными. Когда класс непечатан, производный класс может получить доступ и манипулировать базовые классы, если какие-либо поля данных или методы, которые внутренне манипулируют поля доступны, а не частные. Кроме того, виртуальный метод может быть переопределяется производным классом, а производный класс может решить, следует ли вызовите реализацию базовых классов. Путем создания метода, свойства или события виртуальный, базовый класс отказывается от некоторый контроль над его поведением и его государство. Если тщательно продумать, это может привести к тому, что объект будет вести себя непредсказуемо, и он открывается потенциальные дыры в безопасности.

Ответ 7

Мне не нравится этот способ думать. Java и С# сделаны языками ООП. Эти языки разработаны таким образом, что класс может иметь родителя или ребенка. Что это.

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

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

Ответ 8

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

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

Ответ 9

Это очень упрямый вопрос, который, вероятно, соберет некоторые очень упрямые ответы; -)

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

Ответ 10

"... рассмотрите [как], как их классы должны быть подклассы..." не имеет значения.

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

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

Ответ 11

Я нахожу, что запечатанные/окончательные классы на самом деле довольно редки, по моему опыту; Я бы не рекомендовал предлагать, чтобы все классы были закрыты/окончательны по умолчанию. Эта спецификация делает определенное утверждение о состоянии кода (то есть завершается), что не всегда всегда верно в течение времени разработки.

Я также добавлю, что если оставить класс незапечатанным, требуется больше усилий по разработке/тестированию, чтобы убедиться, что выявленные поведения хорошо определены и протестированы; тяжелое модульное тестирование имеет решающее значение, ИМО, для достижения уровня уверенности в поведении класса, который, как представляется, желателен сторонниками "запечатанных". Но ИМО, что увеличение уровня усилий напрямую переводится на высокий уровень доверия и на более качественный код.

Ответ 12

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

Ответ 13

Твой дом, твое правило.

Вместо этого вы можете иметь дополнительное правило: класс, который может быть подклассифицирован, должен быть аннотирован; никто не должен подклассифицировать класс, который не был аннотирован. Это правило не сложнее, чем ваше правило.