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

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

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

Ответ 1

Шаблоны сложны

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

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

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

Принципы над шаблонами

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

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

  • Программа для "интерфейса", а не "реализация". (Gang of Four 1995: 18)
  • Использовать "композицию объекта" над "наследованием класса". (Gang of Four 1995: 20)

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

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

  • S ingle Принцип ответственности
  • O ручка Закрытый принцип
  • L iskov Принцип замены
  • I Принцип сегрегации nterface
  • D Принцип обращения инверсии

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

Ответ 2

То, что сами авторы шаблонов дизайна больше всего беспокоились, было шаблоном "Посетитель" .

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

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

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

В любом случае, часто вы получаете что-то вроде этого:

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

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

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

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

interface IShape
{
    Area getArea();
}

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

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

Ответ 3

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

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

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

Ответ 4

Я считаю, что шаблон шаблона обычно представляет собой очень опасный шаблон.

  • Много раз он использует иерархию наследования для "неправильных причин".
  • Базовые классы имеют тенденцию к завалению всеми видами недопустимого кода.
  • Это заставляет вас блокировать дизайн, часто довольно рано в процессе разработки. (Преждевременная блокировка во многих случаях)
  • Изменение этого на более позднем этапе становится все сложнее и труднее.

Ответ 5

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

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

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

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

Ответ 6

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

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

Ответ 7

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

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

существуют непрактичные шаблоны, например, например:

  • Interpreter
  • Flyweight

есть и еще сложнее понять, например, например:

  • Abstract Factory. Полный абстрактный шаблон factory с семействами созданных объектов не такой легкий, как кажется.
  • Bridge. Может быть слишком абстрактным, если абстракция и реализация делятся на поддеревья, но в некоторых случаях это очень полезный шаблон.
  • Visitor - Двойное понимание механизма отправки действительно ДОЛЖНО

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

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

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

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

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

Ответ 8

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

Ответ 10

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

Ответ 12

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

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

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

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