Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Design Patterns via C#.pdf
Скачиваний:
154
Добавлен:
17.03.2016
Размер:
13.25 Mб
Скачать

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, но позволяет программистам намного реже использовать его в своей практике.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]