- •Предисловие 15
- •Предисловие
- •От авторов
- •Об авторах
- •Благодарности
- •Принятые в книге обозначения
- •Технические рекомендации
- •Дополнительные ресурсы
- •Глава 1. Введение
- •1.1. Понятие паттерна проектирования
- •Определение
- •Метафора
- •1.2. Формат описания паттернов проектирования
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Пример кода
- •Известные применения паттерна в .Net
- •1.3. Каталог паттернов проектирования
- •Порождающие
- •Структурные
- •Поведенческие
- •1.4. Техники ООП
- •Фабрика - Продукт
- •Фасад - Подсистема
- •Диспетчеризация
- •Цепочка объектов
- •Издатель-Подписчик
- •1.5. Принципы организации каталога
- •Цель паттерна
- •Уровень паттерна
- •1.6. Рекомендации по изучению паттернов
- •1.7. Рекомендации по применению паттернов
- •Глава 2. Порождающие паттерны
- •Игра - Лабиринт
- •Паттерн Abstract Factory
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Пример кода игры «Лабиринт»
- •Известные применения паттерна в .Net
- •Паттерн Builder
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Пример кода игры «Лабиринт»
- •Известные применения паттерна в .Net
- •Паттерн Factory Method
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Пример кода игры «Лабиринт»
- •Известные применения паттерна в .Net
- •Паттерн Prototype
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Пример кода игры «Лабиринт»
- •Известные применения паттерна в .Net
- •Паттерн Singleton
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Пример кода игры «Лабиринт»
- •Известные применения паттерна в .Net
- •Глава 3. Структурные паттерны
- •Паттерн Adapter
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Adapter уровня классов
- •Adapter уровня объектов
- •Структура паттерна на языке C#
- •Adapter уровня классов
- •Adapter уровня объектов
- •Участники
- •Отношения между участниками
- •Отношения между классами (для адаптера уровня классов)
- •Отношения между классами (для адаптера уровня объектов)
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Adapter уровня классов
- •Adapter уровня объектов
- •Особенности применения паттерна Adapter
- •Реализация
- •Пример кода
- •Известные применения паттерна в .Net
- •Паттерн Bridge
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Пример кода
- •Паттерн Composite
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Известные применения паттерна в .Net
- •Паттерн Decorator
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Известные применения паттерна в .Net
- •Паттерн Facade
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Пример кода
- •Паттерн Flyweight
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Пример кода
- •Известные применения паттерна в .Net
- •Паттерн Proxy
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Пример кода
- •Известные применения паттерна в .Net
- •Глава 4. Паттерны поведения
- •Паттерн Chain of Responsibility
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Пример кода
- •Паттерн Command
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Пример кода
- •Известные применения паттерна в .Net
- •Паттерн Interpreter
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Паттерн Iterator
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Классическое представление
- •Представление Microsoft .NET
- •Структура паттерна на языке C#
- •Классическое представление
- •Представление Microsoft .NET
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Известные применения паттерна в .Net
- •Паттерн Mediator
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Пример кода
- •Паттерн Memento
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Реализация
- •Паттерн Observer
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Модель вытягивания (Pull model)
- •Модель проталкивания (Push model)
- •Структура паттерна на языке C#
- •Модель вытягивания (Pull model)
- •Модель проталкивания (Push model)
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Пример кода
- •Известные применения паттерна в .Net
- •Паттерн State
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Паттерн Strategy
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Применимость паттерна
- •Паттерн Template Method
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Применимость паттерна
- •Результаты
- •Реализация
- •Паттерн Visitor
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Применимость паттерна
- •Результаты
- •Реализация
- •Известные применения паттерна в .Net
- •Библиография
145
Паттерн Flyweight
Название
Приспособленец (Русское название паттерна Flyweight, не отражает точный перевод)
Также известен как
-
Классификация
По цели: структурный По применимости: к объектам
Частота использования
Низкая |
- 1 2 3 4 5 |
Назначение
Паттерн Flyweight – описывает правильное применение техники создания «разделяемых объектов», для получения возможности эффективного использования большого числа объектов.
Введение
На «житейском» уровне сложно придумать достойную аналогию или афористически яркую метафору, описывающую использование паттерна Flyweight. Рассмотрим ситуацию, когда один актер играет в одном кинофильме сразу несколько ролей. Например, Майк Майерс (Mike Myers) сыграл целых три роли в кинофильме «Остин Пауэрс».
При просмотре кинофильма, зрители сопереживая вымыслу концентрируют свое внимание на ролях – «Остине Пауэрсе» или «Докторе Зло», а не на актере исполнителе Майке Майерсе. А многие зрители даже не догадываются о том, что один актер сыграл все эти роли.
В ООП имеются такие принципиально различные виды объектов, которые называются «разделяемые» и «неразделяемые». Сам актер Майк Майерс – является «разделяемым» объектом. Актера
146
разделяют между собой роли-персонажи являющиеся «неразделяемыми» объектами – это роль «Остин Пауэрс» и роль «Доктор Зло». Роль – это полноценный объект состоящий из костюма и грима. Костюм и грим творят чудеса, с их помощью, один и тот же актер может сыграть несколько ролей в одной картине. Важно понимать, что кинозрители не взаимодействуют напрямую с человеком-актером, кинозрители сосредотачивают свое внимание именно на игре роли-персонажа, забывая о человеке, играющем роль. Другими словами, кинозрители могут не помнить имя актера, но помнят и обсуждают поступки самого персонажа в контексте сюжета и фильма. Соответственно кинозрители «клиенты» не взаимодействуют напрямую с актером - «разделяемым» объектом, но взаимодействуют с ролями - «неразделяемыми» объектами. Паттерн Flyweight как раз и описывает способы «правильного обращения» с разделяемыми и неразделяемыми объектами.
Представим рассмотренный пример использования разделяемых и неразделяемых объектов программно.
class Program { static void Main() { ActorMikeMyers mike = new ActorMikeMyers();
RoleAustinPowers austin = new RoleAustinPowers(mike); austin.Greeting("Hello! I'm Austin Powers!");
RoleDoctorEvil dr = new RoleDoctorEvil(mike); dr.Greeting("Hello! I'm Dr.Evil!"); } }
abstract class Flyweight { public abstract void Greeting(string speech); }
|
|
// Неразделяемый. |
|
|
|
class RoleAustinPowers |
: Flyweight |
|
|
{ |
|
|
|
Flyweight flyweight; |
|
|
|
public RoleAustinPowers(Flyweight flyweight) |
|
|
|
{ |
|
|
|
this.flyweight |
= flyweight; |
|
|
} |
|
|
|
public override void Greeting(string speech) |
|
|
|
{ |
|
// Разделяемый. |
|
this.flyweight.Greeting(speech); |
|
|
} |
|
|
class ActorMikeMyers |
: Flyweight |
|
|
} |
|
||
{ |
|
|
|
|
|
|
|
public override void Greeting(string speech) |
|
|
|
{ |
|
|
|
Console.WriteLine(speech); |
// Неразделяемый. |
|
|
} |
|
|
|
|
class RoleDoctorEvil : |
Flyweight |
|
} |
|
||
|
{ |
|
|
|
|
|
|
|
|
Flyweight flyweight; |
|
|
|
public RoleDoctorEvil(Flyweight flyweight) |
|
|
|
{ |
|
|
|
this.flyweight |
= flyweight; |
|
|
} |
|
|
|
public override void Greeting(string speech) |
|
|
|
{ |
|
|
|
this.flyweight.Greeting(speech); |
|
|
|
} |
|
|
|
} |
|
См. Пример к главе: \011_Flyweight\003_ComedyFilm
Диаграмма классов будет выглядеть следующим образом:
147
См. Пример к главе: \011_Flyweight\003_ComedyFilm
Возникает ряд вопросов. Зачем разделять объекты на «разделяемые» и «неразделяемые»? Где эти объекты использовать в своих программах? Почему указана такая низкая частота использования паттерна
Flyweight?
Для того, чтобы ответить на эти вопросы, следует вспомнить различия между объектами и экземплярами, которые строятся и размещаются в управляемой куче (Managed heap). На рисунке ниже показано, как происходит разделение «исполняемой сущности» на объект и экземпляры. Объект – это область динамической памяти, которая содержит в себе методы (и статические поля). Экземпляр – это область динамической памяти, которая содержит в себе только нестатические поля.
Как видно из рисунка у класса может быть только один объект и сколько угодно экземпляров. Локальные переменные a и b из метода Main содержат ссылки (адреса памяти) на экземпляры. Экземпляры «a» и «b» в свою очередь содержат в специальном служебном блоке (заголовке) адрес самого объекта. На рисунке синими (прямыми) стрелками показана ссылочность: «переменная» - «экземпляр» - «объект». Красная (пунктирная) линия показывает «маршрут» прохождения запроса (вызова метода). Более детально познакомится с организацией взаимодействий между объектом и экземплярами можно в книге Джефри Рихтера – «CLR via C#».
Разделение «программной сущности уровня выполнения» на объект и экземпляры, было организовано с целью добиться экономии использования оперативной памяти. Важно понимать, что тело любого метода (функции или процедуры) представляет собой набор инструкций C#, которые будут преобразованы компилятором csc.exe (С Sharp Compiler) в байт-код который будет подаваться на вход виртуальной машины (интерпретатора, компилирующего (JIT) типа) CLR (C:\Windows\System32\mscoree.dll).
148
Байт-код тела метода занимает собой определенный объем оперативной памяти и если этот код дублировать в каждом экземпляре, то такой подход может оказаться не эффективным с точки зрения расходования памяти. Поэтому код метода выносится в отдельную исполняемую сущность, которая называется объектом. Экземпляры же в себе хранят только нестатические поля.
Также следует знать, что имеется возможность использовать только объект без построения экземпляра. Прямое обращение к объекту возможно при наличии в программе статического класса или статических членов нестатического класса. На рисунке ниже показано, как происходит прямое обращение к объекту статического класса. В таком случае в программе имеется только «разделяемая» сущность (объект) при отсутствии «неразделяемых» (экземпляров). В нотации ООП строка StaticClass.Method() – читается так: на «классе-объекте» StaticClass вызывается метод с именем Method.
Всвою очередь построение только одного экземпляра «неразделяемого», без объекта невозможно
иэто очевидно, так как все классы неявно наследуются от базового класса Object, который содержит в себе набор методов, которые и будут размещены в объекте.
Помимо рассмотрения техник разделения на «разделяемые объекты» и «неразделяемые объекты», следует сделать акцент на таких понятиях как «внутреннее состояние» и «внешнее состояние».
Известно, что состояние объекта представляется совокупностью значений полей этого объекта.
Принято называть состояние «разделяемого объекта» - «внутренним состоянием», а состояние «неразделяемого объекта» - «внешним состоянием».
Из всего сказанного выше легко видеть, что паттерн Flyweight нашел свое выражение в организации структуры исполняемых сущностей платформы .Net, и идея использования техники «разделяемых» и «неразделяемых» объектов красной нитью проходит через всю архитектуру организации работы динамической управляемой памяти в .Net. Объекты – представлены в динамической памяти как «разделяемые» сущности, а экземпляры – представлены как «неразделяемые» сущности. Объект – разделяется между несколькими экземплярами, также как актер между несколькими ролями.
Организация разделения «программных сущностей уровня выполнения» на объекты и экземпляры, не избавляет совсем от надобности использования паттерна Flyweight, но позволяет программистам намного реже использовать его в своей практике.