Паттерн «Мост» (Bridge) Описание и пример реализации

Паттерн «Мост» предназначен для оптимизации сложных структур объектов.

Его смысл в том, чтобы разделить абстракцию и реализацию таким образом, чтобы они могли изменяться независимо друг от друга. Это даёт весьма положительный эффект, когда абстракция и реализация должны расширяться новыми подклассами или меняется не только сам объект, но и функции, которые он выполняет.

Описание

Паттерн «Мост» включает следующих участников:

  • 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]. Но, для этого паттерна также существует ряд частных случаев, которые обладают меньшей гибкостью, но в определённых ситуациях их применение может быть оправдано.

Примеры кода для них приводить не будем, та как в подавляющем большинстве случаев речь идёт об упрощении архитектуры паттерна.

  • Объединение абстракций.
    Если уточнённая абстракция только одна, то необходимость в базовом классе абстракции по сути отпадает. Но, если необходимость расширения архитектуры не исключена лучше использовать классический вариант;
  • Исключение произвольного задания реализации.
    Если данная уточнённая абстракция должна работать только с определённым списком реализаторов, имеет смысл ограничить их выбор либо исключить его вовсе.
    Пример последнего, конструктор класса уточнённой реализации не принимающий в качестве параметра реализатор. Вместо этого реализатор по умолчанию прописан в коде класса.
  • Исключение смены реализации «на ходу».
    Если реализация, которая используется уточнённой абстракцией не должна меняться, целесообразно исключить члены класса, которые обеспечивают такую возможность.
Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *