Design Patterns: Elements of Reusable Object-Oriented Software (1994) — книга по программной инженерии, описывающая шаблоны проектирования программного обеспечения . Книга была написана Эрихом Гаммой , Ричардом Хелмом , Ральфом Джонсоном и Джоном Влиссидесом , с предисловием Грэди Буча . Книга разделена на две части: в первых двух главах изучаются возможности и подводные камни объектно-ориентированного программирования, а в остальных главах описываются 23 классических шаблона проектирования программного обеспечения . В книгу включены примеры на C++ и Smalltalk .
Он оказал влияние на область разработки программного обеспечения и считается важным источником для теории и практики объектно-ориентированного проектирования. Было продано более 500 000 экземпляров на английском и 13 других языках. [1] Авторов часто называют « Бандой четырех» (GoF). [2] [3] [4] [5]
Книга началась на встрече OOPSLA 1990 года на встрече "Towards an Architecture Handbook", где Эрих Гамма и Ричард Хелм встретились и обнаружили общий интерес. Позже к ним присоединились Ральф Джонсон и Джон Влиссидес. [6] Книга была первоначально опубликована 21 октября 1994 года с авторским правом 1995 года и стала доступна публике на встрече OOPSLA 1994 года.
Глава 1 представляет собой обсуждение методов объектно-ориентированного проектирования, основанное на опыте авторов, которые, по их мнению, приведут к качественному объектно-ориентированному проектированию программного обеспечения, включая:
Авторы утверждают, что интерфейсы имеют следующие преимущества перед реализацией:
Использование интерфейса также приводит к динамическому связыванию и полиморфизму , которые являются центральными особенностями объектно-ориентированного программирования.
Авторы называют наследование повторным использованием по принципу «белого ящика» , при этом «белый ящик» относится к видимости, поскольку внутренние компоненты родительских классов часто видны подклассам . Напротив, авторы называют композицию объектов (в которой объекты с четко определенными интерфейсами динамически используются во время выполнения объектами, получающими ссылки на другие объекты) повторным использованием по принципу «черного ящика» , поскольку никакие внутренние детали составных объектов не должны быть видны в коде, использующем их.
Авторы подробно обсуждают противоречие между наследованием и инкапсуляцией и утверждают, что по их опыту, дизайнеры злоупотребляют наследованием (Gang of Four 1995:20). Опасность формулируется следующим образом:
Они предупреждают, что реализация подкласса может стать настолько связанной с реализацией его родительского класса, что любое изменение в реализации родителя заставит подкласс измениться. Более того, они утверждают, что способ избежать этого — наследовать только от абстрактных классов, но затем они указывают на минимальное повторное использование кода.
Использование наследования рекомендуется в основном при расширении функциональности существующих компонентов, повторном использовании большей части старого кода и добавлении относительно небольших объемов нового кода.
Для авторов «делегирование» — это крайняя форма композиции объектов, которая всегда может быть использована для замены наследования. Делегирование включает два объекта: «отправитель» передает себя «делегату», чтобы позволить делегату ссылаться на отправителя. Таким образом, связь между двумя частями системы устанавливается только во время выполнения, а не во время компиляции. В статье Callback есть дополнительная информация о делегировании.
Авторы также обсуждают так называемые параметризованные типы, которые также известны как обобщенные типы ( Ada , Eiffel , Java , C# , Visual Basic (.NET) и Delphi ) или шаблоны ( C++ ). Они позволяют определить любой тип без указания всех других типов, которые он использует — неуказанные типы предоставляются как «параметры» в точке использования.
Авторы признают, что делегирование и параметризация очень эффективны, но добавляют предупреждение:
Авторы далее различают « Агрегацию », когда один объект «имеет» или «является частью» другого объекта (подразумевая, что агрегатный объект и его владелец имеют одинаковое время жизни), и знакомство, когда один объект просто «знает» о другом объекте. Иногда знакомство называют «ассоциацией» или отношением «использования». Объекты знакомства могут запрашивать операции друг у друга, но они не отвечают друг за друга. Знакомство — это более слабая связь, чем агрегация, и предполагает гораздо более слабую связь между объектами, что часто может быть желательно для максимальной поддерживаемости в проектах.
Авторы используют термин «набор инструментов» там, где другие сегодня могли бы использовать «библиотеку классов», как в C# или Java. На их языке наборы инструментов являются объектно-ориентированным эквивалентом библиотек подпрограмм, тогда как «фреймворк » — это набор взаимодействующих классов, которые составляют повторно используемый дизайн для определенного класса программного обеспечения. Они утверждают, что приложения сложно проектировать, наборы инструментов сложнее, а фреймворки сложнее всего проектировать.
Порождающие шаблоны — это те, которые создают объекты, а не создают их напрямую. Это дает программе большую гибкость в принятии решения о том, какие объекты необходимо создать для данного случая.
Структурные шаблоны касаются композиции классов и объектов. Они используют наследование для составления интерфейсов и определяют способы составления объектов для получения новой функциональности.
Большинство поведенческих шаблонов проектирования специально посвящены коммуникации между объектами.
В 2005 году ACM SIGPLAN присудила авторам премию за достижения в области языков программирования того года в знак признания влияния их работы «на практику программирования и разработку языков программирования ». [7]
Критика была направлена на концепцию шаблонов проектирования программного обеспечения в целом и на шаблоны проектирования в частности. Основная критика шаблонов проектирования заключается в том, что их шаблоны являются просто обходными путями для отсутствующих функций в C++, заменяя элегантные абстрактные функции длинными конкретными шаблонами, по сути становясь «человеческим компилятором». Пол Грэм писал: [8]
Когда я вижу закономерности в своих программах, я считаю это признаком проблемы. Форма программы должна отражать только ту проблему, которую она должна решить. Любая другая закономерность в коде является признаком, по крайней мере для меня, того, что я использую абстракции, которые недостаточно мощны, — часто это означает, что я вручную генерирую расширения какого-то макроса, который мне нужно написать.
Питер Норвиг демонстрирует, что 16 из 23 шаблонов в Design Patterns упрощаются или устраняются языковыми особенностями Lisp или Dylan . [9] Связанные наблюдения были сделаны Ханнеманом и Кичалесом, которые реализовали несколько из 23 шаблонов проектирования с использованием аспектно-ориентированного языка программирования ( AspectJ ) и показали, что зависимости на уровне кода были удалены из реализаций 17 из 23 шаблонов проектирования и что аспектно-ориентированное программирование может упростить реализацию шаблонов проектирования. [10]
В интервью InformIT в 2009 году Эрих Гамма заявил, что авторы книги обсуждали в 2005 году, как бы они рефакторили книгу, и пришли к выводу, что они бы переклассифицировали некоторые шаблоны и добавили бы несколько дополнительных, таких как объект расширения/интерфейс, внедрение зависимости, объект типа и нулевой объект. Гамма хотел удалить шаблон Singleton, но среди авторов не было консенсуса по этому поводу. [11]