Введение в паттерны проектирования

Вообще объектно-ориентированное проектирование существует для того чтобы строить более гибкие, модульные, повторно используемые и понятные конструкции.

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

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

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

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

Деление паттернов на категории:

Cамые простые и распространенные паттерны: 

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

Проектирование объектно-ориентированных программ - нелегкое дело, а если их нужно использовать повторно, то все становится еще сложнее. Необходимо:
  • подобрать подходящие объекты, отнести их к различным классам, соблюдая разумную степень детализации;
  • определить интерфейсы классов и иерархию наследования;
  • и установить существенные отношения между классами. 
Дизайн должен, с одной стороны, соответствовать решаемой задаче, с другой - быть общим, чтобы удалось учесть все требования, которые могут возникнуть в будущем.

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

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

Смысл паттерна - предложить решение определенной задачи в конкретном контексте.

Паттерн состоит из четырех основных элементов:
  1. Имя. Сославшись на него, мы можем сразу описать проблему проектирования; ее решения и их последствия. Присваивание паттернам имен позволяет проектировать на более высоком уровне абстракции. С помощью словаря паттернов можно вести обсуждение с коллегами, упоминать паттерны в документации, в тонкостях представлять дизайн системы. Нахождение хороших имен было одной из самых трудных задач при составлении каталога.
  2. Задача. Описание того, когда следует применять паттерн. Необходимо сформулировать задачу и ее контекст. Может описываться конкретная проблема проектирования, например способ представления алгоритмов в виде объектов. Иногда отмечается, какие структуры классов или объектов свидетельствуют о негибком дизайне. Также может включаться перечень условий, при выполнении которых имеет смысл применять данный паттерн.
  3. Решение. Описание элементов дизайна, отношений между ними, функций каждого элемента. Конкретный дизайн или реализация не имеются в виду, поскольку паттерн - это шаблон, применимый в самых разных ситуациях. Просто дается абстрактное описание задачи проектирования и того, как она может быть решена с помощью некоего весьма обобщенного сочетания элементов (в нашем случае классов и объектов).
  4. Результаты - это следствия применения паттерна и разного рода компромиссы. Хотя при описании проектных решений о последствиях часто не упоминают, знать о них необходимо, чтобы можно было выбрать между различными вариантами и оценить преимущества и недостатки данного паттерна. Здесь речь идет и о выборе языка и реализации. Поскольку в объектно-ориентированном проектировании повторное использование зачастую является важным фактором, то к результатам следует относить и влияние на степень гибкости, расширяемости и переносимости системы. Перечисление всех последствий поможет вам понять и оценить их роль.

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

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

Поскольку любой проект в конечном итоге предстоит реализовывать, в состав паттерна включается пример кода на языке C++ (иногда на Smalltalk), иллюстрирующего реализацию. Хотя, строго говоря, паттерны используются в проектировании, они основаны на практических решениях, реализованных на основных языках объектно-ориентированного программирования типа Smalltalk и C++, а не на процедурных (Pascal, С, Ada и т.п.) или объектно-ориентированных языках с динамической типизацией (CLOS, Dylan, Self). В наших паттернах подразумевается использование возможностей Smalltalk и C++, и от этого зависит, что реализовать легко, а что - трудно. Если бы мы ориентировались на процедурные языки, то включили бы паттерны наследование, инкапсуляция и полиморфизм. Некоторые из наших паттернов напрямую поддерживаются менее распространенными языками. Так, в языке CLOS есть мультиметоды, которые делают ненужным паттерн посетитель. Собственно, даже между Smalltalk и C++ есть много различий, из-за чего некоторые паттерны проще выражаются на одном языке, чем на другом (см., например, паттерн итератор).


--