Паттерны проектирования, которых следует избегать [закрыто]

105

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

Мой вопрос : есть ли другие шаблоны проектирования, которых следует избегать или использовать с большой осторожностью?

Брайан Расмуссен
источник
Я просто должен отметить большой список Design Antipatterns deviq.com/antipatterns
Developer
@casperOne, почему ты закрыл вопрос? Вопрос был законным.
bleepzter

Ответы:

149

Узоры сложные

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

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

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

Принципы важнее шаблонов

Использование шаблонов может показаться спорным, если они явно могут привести к чрезмерно продуманным и сложным решениям. Однако программисту гораздо интереснее ознакомиться с методами и принципами проектирования, которые лежат в основе большинства шаблонов. Фактически, одна из моих любимых книг о «шаблонах проектирования» подчеркивает это , повторяя, какие принципы применимы к рассматриваемому шаблону. С точки зрения релевантности они достаточно просты, чтобы быть полезными, чем шаблоны. Некоторые из принципов являются достаточно общими, чтобы охватывать нечто большее, чем объектно-ориентированное программирование (ООП), например, принцип подстановки Лискова , если вы можете создавать модули своего кода.

Существует множество принципов проектирования, но те, что описаны в первой главе книги GoF , весьма полезны для начала.

  • Программируйте «интерфейс», а не «реализацию». (Банда четырех 1995: 18)
  • Отдавайте предпочтение «композиции объекта» над «наследованием класса». (Банда четырех 1995: 20)

Позвольте им на время погрузиться в вас. Следует отметить, что, когда был написан GoF, интерфейс означал все, что является абстракцией (что также означает суперклассы), не путать с интерфейсом как типом в Java или C #. Второй принцип исходит из наблюдаемого чрезмерного использования наследования, которое, к сожалению, все еще распространено сегодня .

Оттуда вы можете прочитать о принципах SOLID, о которых рассказал Роберт Сесил Мартин (он же дядя Боб) . Скотт Хансельман взял интервью у дяди Боба в подкасте об этих принципах :

  • S Ingle Ответственность Принцип
  • Принцип замкнутости O pen
  • L Иськов принцип замещения
  • Я nterface сегрегация Принцип
  • D ependency Принцип инверсии

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

Spoike
источник
7
+1 Очень хороший ответ. Кажется, что каждый (новичок) программист сегодня знает свои шаблоны проектирования или, по крайней мере, знает, что они существуют. Но очень многие никогда не слышали, не говоря уже о том, чтобы применять некоторые из абсолютно важных принципов, таких как единственная ответственность, для управления сложностью своего кода.
eljenso
21

Самых авторов Design Patterns больше всего беспокоил паттерн «Посетитель».

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

Альтернативное имя для шаблона «Посетитель» - «Мульти-отправка», потому что шаблон «Посетитель» - это то, что вы получаете, когда хотите использовать однотипный язык объектно-ориентированного диспетчерского управления, чтобы выбрать код для использования на основе типа двух. (или более) разные предметы.

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

Во всяком случае, часто получается что-то вроде этого:

interface IShape
{
    double intersectWith(Triangle t);
    double intersectWith(Rectangle r);
    double intersectWith(Circle c);
}

Проблема в том, что вы объединили вместе все свои реализации «IShape». Вы подразумевали, что всякий раз, когда вы хотите добавить новую фигуру в иерархию, вам нужно будет также изменить все другие реализации «фигуры».

Иногда это правильный минималистичный дизайн, но подумайте над этим. Действительно ли ваш дизайн требует отправки на два типа? Готовы ли вы написать каждый из комбинаторных взрывов мульти-методов?

Часто, вводя другую концепцию, вы можете уменьшить количество комбинаций, которые вам на самом деле придется написать:

interface IShape
{
    Area getArea();
}

class Area
{
    public double intersectWith(Area otherArea);
    ...
}

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

Пол Холлингсворт
источник
2
Говоря о посетителях, дядя Боб использует его «все время». Butunclebob.com/ArticleS.UncleBob.IuseVisitor
Spoike
3
@Paul Hollingsworth. Не могли бы вы дать ссылку, где говорится, что авторы шаблонов проектирования обеспокоены (и почему они обеспокоены)?
m3th0dman
16

Синглтоны - класс, использующий одноэлементный X, имеет от него зависимость, которую трудно увидеть и которую трудно изолировать для тестирования.

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

См. Синглтоны - патологические лжецы .

orip
источник
1
Они также могут просто провести тестирование, поскольку могут дать вам одну точку для внедрения Mock-объекта. Все дело в правильном балансе.
Мартин Браун
1
@Martin: Если, конечно, можно изменить синглтон для тестирования (если вы не используете стандартную реализацию сингелтона), но как это проще, чем передать реализацию теста в конструкторе?
orip
14

Я считаю, что шаблон "Метод шаблона" в целом очень опасен.

  • Часто он использует вашу иерархию наследования "по неправильным причинам".
  • Базовые классы имеют тенденцию засоряться разного рода несвязанным кодом.
  • Это заставляет вас ограничивать дизайн, часто довольно рано в процессе разработки. (Во многих случаях преждевременная блокировка)
  • Изменить это на более позднем этапе становится все труднее и труднее.
Кросенвольд
источник
2
Я бы добавил, что всякий раз, когда вы используете шаблонный метод, вам, вероятно, лучше использовать стратегию. Проблема с TemplateMethod заключается в том, что между базовым классом и производным классом существует повторная входимость, которая часто излишне связана.
Пол Холлингсворт,
5
@Paul: Шаблонный метод хорош при правильном использовании, то есть когда части, которые меняются, должны знать много о частях, которые этого не делают. Я считаю, что стратегия должна использоваться, когда базовый код вызывает только настраиваемый код, а метод шаблона должен использоваться, когда настраиваемый код по своей сути должен знать о базовом коде.
dsimcha
да, дсимча, я согласен ... пока конструктор классов знает об этом.
Пол Холлингсворт,
9

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

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

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

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

Megacan
источник
7

Я думаю, что Active Record - это чрезмерно используемый шаблон, который поощряет смешивание бизнес-логики с кодом устойчивости. Он не очень хорошо скрывает реализацию хранилища от уровня модели и связывает модели с базой данных. Существует множество альтернатив (описанных в PoEAA), таких как Table Data Gateway, Row Data Gateway и Data Mapper, которые часто обеспечивают лучшее решение и, безусловно, помогают обеспечить лучшую абстракцию хранилища. Кроме того, вашу модель не нужно хранить в базе данных; как насчет хранения их в формате XML или доступа к ним с помощью веб-служб? Насколько легко было бы изменить механизм хранения ваших моделей?

Тем не менее, Active Record не всегда плох и идеально подходит для более простых приложений, где других возможностей было бы слишком много.

Тим Уордл
источник
1
Довольно верно, но в некоторой степени зависит от реализации.
Майк Вудхаус
6

Это просто ... избегайте шаблонов проектирования, которые вам непонятны или которые вам не подходят .

Чтобы назвать некоторые ...

есть некоторые непрактичные шаблоны , например:

  • Interpreter
  • Flyweight

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

  • Abstract Factory - Полный абстрактный фабричный паттерн с семействами созданных объектов не такой простой, как кажется
  • Bridge - Может стать слишком абстрактным, если абстракция и реализация разделены на поддеревья, но в некоторых случаях это очень удобный шаблон
  • Visitor - Понимание механизма двойной отправки действительно ОБЯЗАТЕЛЬНО

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

  • Singleton - не совсем плохой узор, просто СЛИШКОМ злоупотребляют (часто там, где он не подходит)
  • Observer - отличный паттерн ... просто затрудняет чтение и отладку кода
  • Prototype - компилятор торгов проверяет динамизм (что может быть хорошо или плохо ... зависит)
  • Chain of responsibility - слишком часто просто принудительно / искусственно впихнуты в дизайн

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

Для тех, кто «труднее понять» ... они действительно очень помогают, когда используются в подходящих местах и ​​когда они хорошо реализованы ... но они становятся кошмаром при неправильном использовании.

Теперь, что дальше ...

Марсель Тот
источник
Шаблон-легковес необходим в любое время, когда вы используете ресурс, часто изображение, более одного раза. Это не шаблон, это решение.
Дженгиз
5

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

фальстро
источник
Интересно читает. Спасибо за ссылки!
Bombe
3
Дебилы производят плохой код. Неужели идиоты с шаблонами создают код хуже, чем дебилы, которые никогда не видели шаблонов? Я так не думаю. Для умных людей шаблоны представляют собой хорошо известный словарный запас, который облегчает обмен идеями. Решение: изучать шаблоны и иметь дело только с умными программистами.
Мартин Браун
Я не думаю, что настоящий идиот действительно может создать худший код - независимо от того, какой инструмент он использует
1800 ИНФОРМАЦИЯ
1
Я думаю, что его пример с его тестом в колледже только доказывает, что люди, которые презирают свою проблемную область и не хотят изучать ее более нескольких часов в течение одного уик-энда, будут давать неправильные ответы при попытке решить проблемы.
скриптокалипсис
5

Некоторые говорят, что локатор сервисов - это антипаттерн.

Арнис Лапса
источник
Также важно отметить, что иногда требуется локатор услуг. Например, если у вас нет надлежащего контроля над созданием объекта (например, атрибуты с непостоянными параметрами в C #). Но также можно использовать локатор сервисов с внедрением ctor.
Sinaesthetic
2

Я считаю, что шаблону наблюдателя есть за что ответить, он работает в очень общих случаях, но по мере того, как системы становятся более сложными, он становится кошмаром, требуя уведомлений OnBefore (), OnAfter () и часто публикации асинхронных задач, чтобы избежать повторного запуска. вступление. Гораздо лучшим решением является разработка системы автоматического анализа зависимостей, которая отслеживает доступ ко всем объектам (с барьерами чтения) во время вычислений и автоматически создает ребро в графе зависимостей.

Джесси Пеппер
источник
4
Я понял все в вашем ответе вплоть до слова «А»
1800 ИНФОРМАЦИЯ
Возможно, вам потребуется расширить или связать этот автоматический анализ зависимостей, о котором вы говорите. Также в .NET делегаты / события используются вместо шаблона наблюдателя.
Spoike
3
@Spoike: делегаты / события являются реализацией шаблона наблюдателя
orip
1
Мое личное недовольство Observer заключается в том, что он может создавать утечки памяти в языках со сборщиком мусора. Когда вы закончите работу с объектом, вам нужно помнить, что он не будет очищен.
Мартин Браун
@orip: да, именно поэтому вы используете делегаты / события. ;)
Spoike
2

Дополнение к сообщению Спойка, Refactoring to Patterns - хорошее чтение.

Адил Ансари
источник
Я действительно связался с каталогом книги в Интернете. :)
Spoike
Ой! Я не стал его парить. Собственно, сразу после того, как я задал вопрос, эта книга пришла мне в голову, и тогда я увидел ваш ответ. Я не мог удержаться, чтобы опубликовать это. :)
Adeel Ansari
0

Итератор - это еще один шаблон GoF, которого следует избегать или, по крайней мере, использовать его только тогда, когда нет альтернативы.

Альтернативы:

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

  2. селекторы а-ля LINQ или jQuery. Их следует использовать, когда for-each не подходит, потому что не все объекты из контейнера должны обрабатываться. В отличие от итераторов, селекторы позволяют в одном месте указать, какие объекты нужно обрабатывать.

Владимир Фролов
источник
Я согласен с селекторами. Foreach - это итератор, большинство объектно-ориентированных языков предоставляют итеративный интерфейс, который вы реализуете, чтобы разрешить foreach.
Нил Эйткен
В некоторых языках конструкция for-each может быть реализована с помощью итераторов, но на самом деле концепция этого более высокоуровневая и ближе к селекторам. При использовании for-каждый разработчик явно заявляет, что все элементы из контейнера должны быть обработаны.
Владимир Фролов
Итераторы - отличный паттерн. Анти-шаблон будет реализовывать IEnumerable / IEnumerator без итератора. Я считаю, что LINQ стал возможным благодаря yieldитератору. Эрик Уайт хорошо обсудил это в C # 3.0: blogs.msdn.com/b/ericwhite/archive/2006/10/04/… . Также ознакомьтесь с обсуждением сопрограмм с итераторами Джереми Ликнесса: wintellect.com/CS/blogs/jlikness/archive/2010/03/23/… .
@Ryan Riley, итераторы - это объекты низкого уровня, и поэтому их следует избегать при разработке и коде высокого уровня. Детали реализации итераторов и различных селекторов здесь не имеют значения. Селекторы, в отличие от итераторов, позволяют программисту явно выражать то, что они хотят обработать, и поэтому они находятся на высоком уровне.
Владимир Фролов
Fwiw, альтернативный LINQ-подобный синтаксис F # - это `List.map (fun x -> x.Value) xs`, который примерно равен объему списка.