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

109

Участники

Abstraction - Абстракция:

Предоставляет интерфейс для абстракции. Хранит ссылку на Implementor.

RefinedAbstraction - Уточненная абстракция:

Расширяет интерфейс, предоставляемый абстракцией.

Implementor - Реализатор:

Предоставляет интерфейс для реализации. Чаще всего класс Implementor предоставляет низкоуровневый интерфейс, а Abstraction предоставляет высокоуровневый интерфейс.

ConcreteImplementor - Конкретный реализатор:

Реализует интерфейс класса Implementor.

Отношения между участниками

Отношения между классами

Абстрактный класс Abstraction связан связью отношения агрегации с абстрактным классом

Implementor.

Конкретный класс RefinedAbstraction связан связью отношения наследования с абстрактным классом Abstraction.

Конкретные классы-реализаторы ConcreteImplementorA и ConcreteImplementorB связаны связью отношения наследования с абстрактным классом Implementor.

Отношения между объектами

Объекты типа Abstraction перенаправляют запросы клиента объектам типа Implementor.

Мотивация

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

Microsoft Windows и стиль Mac OS).

110

Создадим две иерархии, одну для интерфейсов окон (Window, MSWindow и MacWindow), а другую для реализаций элементов управления определенного стиля (WindowImp, MSWindowImp и MacWindowImp). Так, например, подкласс MSWindowImp предоставляет реализацию в стиле Microsoft Windows.

Все методы классов (MSWindow и MacWindow) производных от класса Window, используют методы из классов (MSWindowImp и MacWindowImp) производных от класса WindowImp. Такой подход отделяет абстракцию окна определенного стиля (например, MSWindow) от деталей реализации каждого отдельного элемента стиля (Form, Button и др.).

На диаграмме классов видно, что класс Window является вершиной иерархии абстракций, а класс WindowImp является вершиной иерархии реализаций (параллельной иерархии абстракций). Связь отношения агрегации между классами Window и WindowImp называется мостом. Мост между абстракцией

(Window, MSWindow и MacWindow) и реализацией (WindowImp, MSWindowImp и MacWindowImp). Это позволяет изменять абстракцию и реализацию независимо друг от друга.

См. Пример к главе: \007_Bridge\002_BridgeMotivation

Применимость паттерна

Паттерн Bridge рекомендуется использовать, когда:

Требуется избежать постоянной привязки абстракции к реализации. Иногда бывает необходимо выбирать нужную реализацию во время выполнения программы.

Требуется предоставить возможность расширения новыми подклассами и абстракции, и реализации.

Необходимо разделять одну реализацию между несколькими объектами и этот факт требуется скрыть от клиента. Примером этому может служить использование класса String и таблицы интернирования строк.

Необходимо избавиться от графов наследований, вложенных в графы наследования.

Параллельная иерархия всегда предпочтительней вложенного графа наследования.

Результаты

111

Паттерн Bridge обладает следующими преимуществами:

Отделение реализации от абстракции.

Реализация (Implementor) не имеет привязки к абстрактному интерфейсу абстракции (Abstraction), как это могло бы быть в случае использования вложенных графов наследования. Реализацию абстракции (RefinedAbstraction) можно конфигурировать во время выполнения программы, просто подставляя объекты нужных классов (ConcreteImplementorA или

ConcreteImplementorB). Разделение Abstraction и Implementor устраняет зависимости между абстракцией и реализацией во время компиляции, т.е., позволяет изменять абстракцию и реализацию независимо друг от друга.

Повышение степени расширяемости.

Имеется возможность независимо друг от друга расширять иерархии классов Abstraction и Implementor.

Сокрытие реализации от клиента.

От клиента можно скрыть наличие иерархии реализации (Implementor), предоставив только высокоуровневый интерфейс иерархии абстракции (Abstraction), за которым будет скрываться низкоуровневый интерфейс иерархии реализации (Implementor).

Реализация

Полезные приемы реализации паттерна Bridge:

Наличие только одного класса Implementor.

В том случае, если в программе имеется только одна реализация (ConcreteImplementor), то создавать абстрактный класс Implementor необязательно. Это частный случай использования паттерна Bridge, когда RefinedAbstraction ссылается на ConcreteImplementor. Тем не менее такое разделение полезно, так как позволит изменять ConcreteImplementor, при этом не перекомпилируя клиентскую часть кода.

Создание нужного объекта класса ConcreteImplementor.

Как принимается решение о том, экземпляр какого конкретного реализатора

(ConcreteImplementorA или ConcreteImplementorB) требуется создать? Если у класса RefinedAbstraction имеется информация о классах ConcreteImplementor, то класс

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

Hashtable.

См. Пример к главе: \007_Bridge\003_BridgeCollections

112

Пример кода

Предлагается рассмотреть пример, из раздела «Мотивация», где рассматривается структура приложения, использующего различные стили пользовательского интерфейса (например, стиль Microsoft Windows и стиль Mac OS). Рассмотрим класс Window, который стоит на вершине иерархии абстракций и задает высокоуровневую базовую абстракцию для окна клиентских приложений:

abstract class Window

{

protected WindowImp implementor; protected Form form;

protected Button button;

// Operation

public virtual void Draw()

{

this.form.Controls.Add(button); Application.EnableVisualStyles(); Application.Run(this.form);

}

}

Класс Window содержит поле implementor типа WindowImp. Тип WindowImp представлен в виде абстрактного класса, в котором задан интерфейс взаимодействия с оконной системой. WindowImp является вершиной иерархии реализаций:

abstract class WindowImp

{

protected Button button; protected Form form;

public abstract Form DevDrawForm(); public abstract Button DevDrawButton();

}

Классы MSWindow и MacWindow, производные от класса Window являются представителями иерархии абстракций и определяют разнообразные варианты окон с различным внешним видом форм и кнопок:

class MacWindow : Window

{

public MacWindow()

{

this.implementor = new MacWindowImp(); this.form = this.implementor.DevDrawForm(); this.button = this.implementor.DevDrawButton();

}

// Operation

public override void Draw()

{

form.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Fixed3D; base.Draw();

}

}

113

class MSWindow : Window

{

public MSWindow()

{

this.implementor = new MSWindowImp(); this.form = this.implementor.DevDrawForm();

this.button = this.implementor.DevDrawButton();

}

// Operation

public override void Draw()

{

form.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; base.Draw();

}

}

Конкретными представителями иерархии реализаций являются подклассы MacWindowImp и MSWindowImp класса WindowImp:

class MacWindowImp : WindowImp

{

public override Form DevDrawForm()

{

this.form = new Form(); this.form.AutoScaleDimensions = new SizeF(6F, 13F); this.form.AutoScaleMode = AutoScaleMode.Font; this.form.ClientSize = new Size(284, 172);

this.form.Name = "Mac Form"; this.form.Text = "Mac OS - Snow Leopard"; this.form.BackColor = Color.White;

return this.form;

}

public override Button DevDrawButton()

{

this.button = new Button(); this.button.Location = new Point(75, 70); this.button.Size = new Size(125, 25); this.button.Text = "Leopard"; this.button.ForeColor = Color.White; this.button.BackColor = Color.LightGray;

return this.button;

}

}

class MSWindowImp : WindowImp

{

public override Form DevDrawForm()

{

this.form = new Form(); this.form.AutoScaleDimensions = new SizeF(6F, 13F); this.form.AutoScaleMode = AutoScaleMode.Font; this.form.ClientSize = new Size(284, 172);

this.form.Name = "Microsoft Form"; this.form.Text = "Windows Explorer";

114

this.form.BackColor = Color.LightBlue;

return this.form;

}

public override Button DevDrawButton()

{

this.button = new Button(); this.button.Location = new Point(75, 70); this.button.Size = new Size(125, 25); this.button.Text = "Windows"; this.button.ForeColor = Color.Aqua; this.button.BackColor = Color.DarkBlue;

return this.button;

}

}

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