Паттерн «Мост» предназначен для оптимизации сложных структур объектов.
Его смысл в том, чтобы разделить абстракцию и реализацию таким образом, чтобы они могли изменяться независимо друг от друга. Это даёт весьма положительный эффект, когда абстракция и реализация должны расширяться новыми подклассами или меняется не только сам объект, но и функции, которые он выполняет.
Описание
Паттерн «Мост» включает следующих участников:
- Abstarction – абстракция.
Определяет интерфейс абстракции и хранит ссылку на объект Implementor; - RefinedAbstraction – уточнённая абстракци.
Расширяет интерфейс определённый Abstraction; - Implementor – реализатор.
Определяет интерфейс реализации. Интерфейс реализации необязательно должен совпадать с интерфейсом абстрации; - ConcretteImplementor – конкретный реализатор.
Содержит конкретную реализацию интерфейса класса Implementor; - Client – использует объекты Abstraction.
Ниже приведена диаграмма классов паттерна «Мост».
Примеры реализации
Пример на C#
Создаём базовый класс абстракции:
abstract class Abstraction { private Implementor _imp; public Implementor Implementor { set { _imp = value; } } public Abstraction(Implementor implementor) { _imp = implementor; } public virtual void Operation() { _imp.OperationImp(); } }
Создаём класс уточнённой абстракции:
class RefinedAbstracion:Abstraction { public RefinedAbstracion(Implementor implementor):base(implementor) { } public override void Operation() { base.Operation(); } }
Опишем интерфейс реализатора:
interface Implementor { void OperationImp(); }
И два конкретных реализатора. Конкретный реализатор «A»:
class ConcretteImplementorA : Implementor { public void OperationImp() { Console.WriteLine(2*2); } }
Конкретный реализатор «B»:
class ConcretteImplementorB : Implementor { public void OperationImp() { Console.WriteLine(4*4); } }
Работу паттерна можно продемонстрировать на простом примере:
//Начальная инициализация с первым вариантом реализации RefinedAbstracion refinedAbstraction = new RefinedAbstracion(new ConcretteImplementorA()); refinedAbstraction.Operation(); //Изменяем используемый вариант реализации refinedAbstraction.Implementor = new ConcretteImplementorB(); refinedAbstraction.Operation();
Паттерн «Мост» позволяет задавать реализацию, как при создании объекта абстракции, так и в процессе работы с ним меняя её «на ходу».
Пример на Delphi
Теперь рассмотрим реализацию паттерна «Мост» на языке программирования Delphi.
Базовый класс абстракции:
type TAbstraction = class abstract private imp: TImplementor; public property Implementor: TImplementor write imp; constructor Create(Implementor: TImplementor); procedure Operation; virtual; end . . . constructor TAbstraction.Create(Implementor: TImplementor); begin imp := Implementor; end; procedure TAbstraction.Operation; begin imp.OperaionImp; end;
Класс уточнённой абстракции:
type TRefinedAbstraction = class(TAbstraction) public constructor Create(Implementor: TImplementor); procedure Operation; override; end; . . . constructor TRefinedAbstraction.Create(Implementor: TImplementor); begin inherited Create(Implementor); end; procedure TRefinedAbstraction.Operation; begin inherited; end;
Далее создадим базовый класс реализатора. В Delphi отсутствует полноценная поддержка интерфейсов. Поэтому реализация паттерна строится полностью на основе абстрактных классов.
type TImplementor = class abstract public procedure OperaionImp; virtual; abstract; end;
Далее напишем два конкретных реализатора.
Конкретный реализатор «A»:
type TConcretteImplementorA = class(TImplementor) procedure OperaionImp; override; end; . . . procedure TConcretteImplementorA.OperaionImp; begin WriteLn(2*2); end;
Конкретный реализатор «B»:
type TConcretteImplementorB = class(TImplementor) procedure OperaionImp; override; end; . . . procedure TConcretteImplementorB.OperaionImp; begin WriteLn(4*4); end;
В итоге получаем реализацию аналогичную той, что была выполнена на C#.
RefinedAbstraction:=TRefinedAbstraction.Create(TConcretteImplementorA.Create); RefinedAbstraction.Operation; RefinedAbstraction.Implementor:=TConcretteImplementorB.Create; RefinedAbstraction.Operation;
Частные случаи
Выше было дано описание и приведены примеры для классического паттерна «Мост», который описан в литературе [1]. Но, для этого паттерна также существует ряд частных случаев, которые обладают меньшей гибкостью, но в определённых ситуациях их применение может быть оправдано.
Примеры кода для них приводить не будем, та как в подавляющем большинстве случаев речь идёт об упрощении архитектуры паттерна.
- Объединение абстракций.
Если уточнённая абстракция только одна, то необходимость в базовом классе абстракции по сути отпадает. Но, если необходимость расширения архитектуры не исключена лучше использовать классический вариант; - Исключение произвольного задания реализации.
Если данная уточнённая абстракция должна работать только с определённым списком реализаторов, имеет смысл ограничить их выбор либо исключить его вовсе.
Пример последнего, конструктор класса уточнённой реализации не принимающий в качестве параметра реализатор. Вместо этого реализатор по умолчанию прописан в коде класса. - Исключение смены реализации «на ходу».
Если реализация, которая используется уточнённой абстракцией не должна меняться, целесообразно исключить члены класса, которые обеспечивают такую возможность.