Выбрать главу

15. Memento (хранитель). Позволяет, не нарушая инкапсуляции, получить и сохранить во внешней памяти внутреннее состояние объекта, чтобы позже объект можно было восстановить точно в таком же состоянии.

16. Observer (наблюдатель). Определяет между объектами зависимость типа "один ко многим", так что при изменении состояния одного объекта все зависящие от него получают извещение и автоматически обновляются.

17. Prototype (прототип). Описывает виды создаваемых объектов с помощью прототипа и создает новые объекты путем его копирования.

18. Proxy (заместитель). Подменяет другой объект для контроля доступа к нему.

19. Singleton (одиночка). Гарантирует, что некоторый класс может иметь только один экземпляр, и предоставляет глобальную точку доступа к нему.

20. State (состояние). Позволяет объекту варьировать свое поведение при изменении внутреннего состояния. При этом создается впечатление, что поменялся класс объекта.

21. Strategy (стратегия). Определяет семейство алгоритмов, инкапсулируя их все и позволяя подставлять один вместо другого. Можно менять алгоритм независимо от клиента, который им пользуется.

22. Template Method (шаблонный метод). Определяет скелет алгоритма, перекладывая ответственность за некоторые его шаги на подклассы. Позволяет подклассам переопределять шаги алгоритма, не меняя его общей структуры.

23. Visitor (посетитель). Представляет операцию, которую надо выполнить над элементами объекта. Позволяет определить новую операцию, не меняя классы элементов, к которым он применяется.

8.8. ПРОЕКТНАЯ ПРОЦЕДУРА ОБЪЕКТНО-ОРИЕНТИРОВАННОГО ПРОЕКТИРОВАНИЯ ПО Б. СТРАУСТРУПУ

8.8.1. Укрупненное изложение проектной процедуры Б. Страуструпа

Б. Страуструп — автор объектно-ориентированного языка программирования C++ с множественным наследованием. У Б. Страуструпа при описании методики проектирования вводится единица проектирования — "компонента". Под компонентой понимается множество классов, объединенных некоторым логическим условием, иногда это общий стиль программирования или описания, иногда — предоставляемый сервис. Ряд авторов вместо термина "компонента" используют термин "модуль".

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

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

Шаг 1. Выделение понятий (классов, порождающих объекты) и установление основных связей между ними.

Шаг 2. Уточнение классов с определением наборов операций (методов) для каждого.

Шаг 3. Уточнение классов с точным определением их зависимостей от других классов. Выясняется наследование и использование зависимостей.

Шаг 4. Задание интерфейсов классов. Более точно определяются отношения классов. Методы разделяются на общие и защищенные. Определяются типы операций над классами.

8.8.2. Шаг 1. Выделение понятий и установление основных связей между ними

Выделение объектов производится во время процесса мысленного представления системы. Часто это происходит как цикл вопросов "что/кто". Команда программистов определяет: что требуется делать? Это немедленно приводит к вопросу: кто будет выполнять действие? Теперь программная система в значительной мере становится похожей на некую организацию. Действия, которые должны быть выполнены, присваиваются некоторому программному объекту в качестве его обязанностей.

Понятия (объекты) соответствуют порождающим классам и могут иметь форму в виде имен существительных и, как экзотика, глаголов и имен прилагательных.

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

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

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

Все классы можно условно разделить на две группы: классы из предметной (прикладной) области и классы, являющиеся артефактами реализации или абстракциями периода реализации.

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

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

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

Классы, являющиеся артефактами реализации или абстракциями периода реализации, — это те понятия, которые применяют программисты и проектировщики для описания методов реализации:

• классы, отражающие ресурсы оборудования (оперативная память, механизмы управления ресурсами, дисковое пространство);

• классы, представляющие системные ресурсы (процессы, потоки ввода-вывода);

• классы, реализующие программные структуры (стеки, очереди, списки, деревья, словари и т. п.);

• другие абстракции, например элементы управления программой (кнопки, меню и т. п.).

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

Пример:

1) классы, представляющие пользовательские понятия (например, легковые машины и грузовики);

2) классы, представляющие обобщения пользовательских понятий (движущиеся средства);

3) классы, представляющие аппаратные ресурсы (например, класс управления памятью);

4) классы, представляющие системные ресурсы (например, выходные потоки);

5) классы, используемые для реализации других классов (например, списки, очереди);

6) встроенные типы данных и структуры управления.

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

(1+2) — представляет пользовательское отражение системы;

(3+4) — представляет машину, на которой будет работать система;

(5+6) — представляет низкоуровневое (со стороны языка программирования) отражение реализации.