Лекция 2. Разработка систем на основе шаблонов

Задачу, над которой вы сейчас работаете, кто-то уже наверняка решал!

Шаблон проектирования (Design Pattern)

Шаблоны проектирования представляют собой стандартные решения периодически повторяющихся проблем.

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

История шаблонов. Строительство

1964. Работы Кристофера Александера в области строительства.

  • Причина: возросшая сложность требований и совершенствование материалов;
  • Общий принцип: отказ от случайных принципов проектирования;
  • Результат: 11 томов проектных решений (опубликованы 8). 243 взаимосвязанных проектных шаблона
    • Waist-High Shelf (полка на уровне пояса)
    • Thickening The Outer Wall (утолщение наружной стены)
    • Things From Your Life (вещи вашей жизни).

История шаблонов. Программное обеспечение

  • 1991. Э. Гамма, Р.Хелм, Р. Джонсон, Д. Влиссидес. Конференция Object-Oriented programming, Languages & Applications:
    • Результатом встречи стала совместная разработка 23 шаблонов проектирования Gang of Four (GoF)
  • 1993. Кент Бек, Вард Каннингам. Привлечение идей Александера к разработке систем на базе метафор:
    • Идеи положены в основу eXtreme Programming
  • 2003. Мартин Фаулер. Patterns of Enterprise Application Architecture.

Зачем учить шаблоны?

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

Вопрос: Если паттерны так хороши, почему никто не оформил их в виде библиотеки?
Ответ: Паттерны относятся к более высокому уровню, чем библиотеки. Они
определяют способы структурирования классов и объектов для решения некоторых задач, а наша задача – адаптировать их для своих конкретных приложений.

Единая номенклатура

Номенклатуры паттернов обладают большой ВЫРАЗИТЕЛЬНОСТЬЮ. Используя паттерны в общении с другим разработчиком или группой, вы передаете не только название паттерна, но целый набор характеристик, качеств и ограничений, представленных данным паттерном.

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

Общение на уровне паттернов помогает дольше оставаться «на уровне архитектуры». Описание программной системы с использованием паттернов позволяет вести обсуждение на более абстрактном уровне, не отвлекаясь на второстепенные подробности реализации объектов и классов.

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

Более увлекательная книга по паттернам для новичков

Состав шаблона (по GoF)

  • Имя. Сославшись на имя мы сразу можем описать проблему проектирования, её решение и следствия;
  • Задача. Описание того, когда следует применять шаблон, т.е. контекст;
  • Решение. Описание элементов дизайна, отношений между ними и функций каждого элемента;
  • Результаты. Следствия применения шаблона и разного рода компромиссы.

Классификация шаблонов проектирования

  • Распределения обязанностей
  • Порождающие
  • Структурные
  • Поведения

GRASP (General Responsibility Assignment Software Patterns — общие шаблоны распределения обязанностей) — паттерны, используемые в ООП для решения общих задач по назначению обязанностей классам и объектам.

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

GRASP-паттерны

  • Information Expert – Информационный эксперт (Эксперт)
  • Creator – Создатель
  • High Cohesion - Высокое зацепление
  • Low Coupling - Низкая связность
  • Pure Fabrication – Чистая синтетика
  • Indirection - Посредник
  • Do Not Talk to Strangers – Не разговаривай с незнакомцами.

Information Expert (Эксперт)

  • Задача. Каков наиболее общий принцип распределения обязанностей между объектами?
  • Решение. Назначить обязанность информационному эксперту – классу у которого имеется вся информация для выполнения обязанности.

Шаблон Information Expert определяет базовый принцип назначения обязанностей. Он утверждает, что обязанности должны быть назначены объекту, который владеет максимумом необходимой информации для выполнения обязанности. Такой объект называется информационным экспертом. Возможно, этот шаблон является самым очевидным из девяти, но вместе с тем и самым важным.

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

Creator

Экземпляры B должны порождать экземпляры A, если:

  • Класс B содержит или агрегирует объекты A;
  • Класс B записывает экземпляры объектов A;
  • Класс B активно использует объекты A;
  • Класс B обладает данными инициализации для объектов A.

Шаблон Creator решает, кто должен создавать объект. Фактически, это применение шаблона Information Expert к проблеме создания объектов. Более конкретно, нужно назначить классу B обязанность создавать экземпляры класса A, если выполняется как можно больше из выше указанных условий.
Альтернативой создателю является шаблон проектирования Фабрика. В этом случае создание объектов концентрируется в отдельном классе.

Controller

  • Задача. Кто должен отвечать за обработку входных системных сообщений?
  • Решение. Делегировать обязанности по обработке системных сообщений классу, удовлетворяющему одному из следующих условий:
    • Класс представляет систему в целом;
    • Класс представляет собой сценарий прецедента:
      • <Прецедент>Controller – описывает шаги прецедента;
      • <Прецедент>Session – состояние выполнения сценария (Применим в stateless-системах, например, WEB).

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

Иногда класс-контроллер представляет всю систему в целом, корневой объект, устройство или важную подсистему (внешний контроллер).

Low Coupling (низкая связанность)

  • Задача. Как снизить влияние изменений и повысить степень повторного использования?
  • Решение. Распределять обязанности, что бы связанность оставалась низкой.

High Cohesion (высокое зацепление)

  • Задача. Как обеспечить возможность управления сложностью?
  • Решение. Распределять обязанности, поддерживая высокую степень зацепления.

Polymorphism

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

Пример: Strategy, State (GoF)

Pure Fabrication («Чистая выдумка» или «Чистая синтетика»)

  • Задача. Какой класс должен обеспечить реализацию Low Coupling и High
  • Cohesion, если Information Expert не обеспечивает подходящего решения?
  • Решение. Присвоить группу обязанностей с высокой степенью зацепления классу, не представляющему конкретного понятия предметной области

    Пример: Production, Repository, (GoF)

Indirection (Непрямое связывание)

  • Проблема. Как распределить обязанности, при отсутствии прямого связывания между объектами?
  • Решение. Присвоить обязанности промежуточному объекту для обеспечения связи между объектами или службами

    Пример : Adapter (GoF), MVC

Protected Variations (Защита от изменений)

Шаблон Protected Variations защищает элементы от изменения других элементов (объектов или подсистем) с помощью вынесения взаимодействия в фиксированный интерфейс. Всё взаимодействие между элементами должно происходить через него. Поведение может варьироваться лишь с помощью создания другой реализации интерфейса.

Разработчик: Хм, но разве дело не сводится к ОО-проектированию? Если я следую принципам инкапсуляции, знаю об абстракции, наследовании и полиморфизме. то зачем мне думать о паттернах проектирования? Для чего тогда были нужны те курсы ОО-проектирования? Я думаю, паттерны проектирования полезны только тем, кто не разбирается
в ОО-проектировании.

Гуру: О, это одно из известных заблуждений объектно-ориентированной разработки: будто знание основ ООП автоматически позволит вам строить гибкие, удобные в сопровождении и при годные к повторному использованию системы.

Разработчик: Нет?

Гуру: Нет. Более того, принципы построения ОО-систем, обладающих
такими свойствами, далеко не всегда очевидны.

Разработчик: Кажется, я начинаю понимать. И на основе этих неочевидных
принципов построения объектно-ориентированных систем
были сформулированы ...

Гуру: ... да, были сформулированы паттерны проектирования.