НЕ МОЛЧИ!!!    Сделай что-нибудь, чтобы остановить войну России в Украине.
...бойтесь людей равнодушных - именно с их молчаливого согласия происходят все самые ужасные преступления на свете.   ("Репортаж с петлёй на шее")

Шаблон проектирования Bridge(Мост)

Рассматривается структурный шаблон проектирования Bridge(Мост), приведено описание шаблона и его реализациия в коде.

Содержание

  • Область применения
  • Реализация
  • Итоги

Область применения

Формальное определение шаблона проектирования Bridge гласит: Bridge  — это структурный шаблон проектирования, используемый при создании программного обеспечения для разделения абстракции и реализации с целью их независимого изменения.
Коротко, но довольно туманно, поэтому попробую пояснить на конкретном упрощенном примере.

Представим, что нам предстоит создать достаточно непростое ПО, где среди прочего необходим определенный функционал о средствах передвижения. Будет логичным выделить его в отдельный класс. В соответствии с ООП создадим, например, абстракцию автомашин Car и будем её реализовывать в классах конкретных средств передвижения примерно так.

Иерархия средств передвижения без использования шаблона Bridge

Часть кода описывающая средства передвижения в проекте может быть достаточно объемной — это классы, иx наследниеи, объекты, их взаимодействие и прочее.

И вот, как обычно бывает в непростом проекте, в исходный код Car были внесены изменения. В итоге вам придется править уже созданный и оттестированный код по всему проекту, что может повлечь за собой ошибки, новое тестирование и прочие неприятные мероприятия.
Минимизировать подобные последствия помогает шаблон проектирования Bridge, который позволяет изолировать жесткую зависимость кода проекта от кода описывающего средства передвижения. Давайте разберемся, за счет чего это происходит.

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

Иерархия средств передвижения с использованием шаблона Bridge

Пунктирная линия со стрелкой отображает связь между созданными иерархиями.

Реализация

Диаграммы хороши, когда надо отобразить общую картину, но, как говорится, дьявол кроется в деталях, поэтому давайте разберемся с шаблоном Bridge на примере.

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

interface Car 
{
	public function _construct(Brand $brand;
	public function getLogo();
	public function getModels();
}

class FordCar implements Car
{
	protected $brand;
	
	public function _construct(Brand $brand)
	{
		$this->$brand = $brand;
	}
	
	public function getLogo()
	{
		return $this->brand->getLogo();
	}
	
	public function getModels()
	{
		return 'The list models of Ford ' . '...';
	}
}

class RenoCar implements Car
{
	protected $brand;
	
	public function _construct(Brand $brand)
	{
		$this->$brand = $brand;
	}
	
	public function getLogo()
	{
		return $this->brand->getLogo();
	}
	
	public function getModels()
	{
		return 'The list models of Renault ' . '...';
	}
}

class BmvCar implements Car
{
	protected $brand;
	
	public function _construct(Brand $brand)
	{
		$this->$brand = $brand;
	}

	public function getLogo()
	{
		return $this->brand->getLogo();
	}
	
	public function getModels()
	{
		return 'The list models of BMV ' .'...';
	}
}

А вот код, реализующий то, что объявлено в предыдущей иерархии.

interface Brand
{
	public function getModels();
	public function getLogo();
}

class FordBrand implements Brand
{
	public function getModels()
	{
		//возвращает список моделей производителя 
	}
	
	public function getLogo()
	{
		//возвращает изображение логотипа производителя
	}
}

class RenoBrand implements Brand
{
	public function getModels()
	{
		//возвращает список моделей производителя 
	}
	
	public function getLogo()
	{
		//возвращает изображение логотипа производителя
	}
}

class BmvBrand implements Brand
{
	public function getModels()
	{
		//возвращает список моделей производителя 
	}
	
	public function getLogo()
	{
		//возвращает изображение логотипа производителя
	}
}

И последнее — как это все работает.

$brand = new FordBrand();
$car = new FordCar($brand);

$image = $car->getLogo();
$list = $car->getModels();
...

Итоги

Что мы теперь имеем в итоге?
При использовании шаблона проектирования Bridge вместо использования классов, в котором жестко связаны интерфейс и его реализация, мы разделили заявленный интерфейс и его реализацию на две независимые иерархии. Что это нам дало?
   На стадии проектирования мы можем параллельно создавать обе иерархии, определив спецификацию интерфейса Car.
   В случае, если нам надо будет добавить нового производителя(новый бренд) в проект, то нам придется лишь добавить новый класс, например, VolvoBrand, код приложения же останется неизменным.
   В случае, если нам придется что-то изменить в интерфейсе средств передвижения, то основные правки придутся на лишь на автономную иерархию Brand, а в иерархии Car нам понадобятся минимальные правки, а этот код как раз и используется приложением.