Дизайн-патерни: Міст (С++)

2 хв. читання

Посилання на статті про породжуючі дизайн-патерни та вихідні коди можна знайти тут.

Структурні дизайн-патерни

  1. Адаптер.
  2. Міст.
  3. Композиція.
  4. Декоратор.
  5. Фасад.
  6. Легковаговик.
  7. Проксі.

Міст (Bridge)

Призначення: розділити реалізацію класу і його абстрактний опис, тим самим дозволяючи змінювати реалізацію класу.

Даний шаблон корисний в тих випадках, коли клас не має якоїсь чіткої реалізації об'єкта, а представляє тільки його абстрактний опис. Реалізація проводиться в класах-нащадках і може бути різною в залежності від використання. В такому класі створюється «міст» – об'єкт, який задаватиме певну імплементацію.

Припустимо, вийшла якась нова суперпотужна гра і вам необхідний ігровий комп'ютер, щоб можна було запустити цю гру і коротати довгі зимові вечори. Але ж ноутбуки є різні, з різним «залізом». Ноутбук певної моделі може мати деякі елементи по замовчуванню, але інші елементи можуть встановлюватися відповідно до потреб. Наприклад, для оптимальної швидкодії гри потрібна потужна відеокарта, яка теж може бути від різних виробників навіть якщо модель ноутбука та ж сама. Якщо ж виробник ноутбука використовував одну модель відеокарти, і раптом знадобилося використати іншу модель, то доведеться перепроектовувати ноутбук з новою відеокартою. Тоді чому б не мати під боком кілька відеокарт і встановлювати потрібну в процесі збірки?

Отже, є опис відеокарти:

class Videocard
{
public:
	Videocard();
	~Videocard();

	virtual void setVideocard() = 0;
	virtual void runVideocard() = 0;
};

Від нього реалізуються конкретні моделі відеокарт, нехай це буде Nvidia 920M:

#include "Videocard.h"

class nvidia920m : public Videocard
{
public:
	nvidia920m();
	~nvidia920m();

	virtual void setVideocard();
	virtual void runVideocard();
};

void nvidia920m::setVideocard()
{
	cout << "NVIDIA GeForce 920m is set up." << endl;
}

void nvidia920m::runVideocard()
{
	cout << "NVIDIA GeForce 920m is running." << endl;
}

та AMD R5:

#include "Videocard.h"

class amdR5 : public Videocard
{
public:
	amdR5();
	~amdR5();

	virtual void setVideocard();
	virtual void runVideocard();
};

void amdR5::setVideocard()
{
	cout << "AMD Radeon R5 is set up." << endl;
}

void amdR5::runVideocard()
{
	cout << "AMD Radeon R5 is running." << endl;
}

Так, не найкращий вибір, але що гроші дозволяють.

Ці відеокарти можуть бути в різних ноутбуках. Але може бути так, що в одній і ті ж моделі ноутбука може бути або одна, або друга наведена відеокарта. Тоді потрібен якийсь інтерфейс, який дозволятиме створювати ноутбук з тією чи іншою відеокартою, тобто міняти реалізацію класу ноутбука:

#include "nvidia920m.h"
#include "amdR5.h"

class Notebook
{
public:
	Notebook();
	~Notebook();

	virtual void setProcessor() = 0;
	virtual void setDisplay() = 0;
	virtual void setVideocard() = 0;

	Videocard* vcard;				// bridge
};

Об'єкт vcard якраз і буде своєрідним мостом, який дозволятиме реалізувати клас Notebook з тією чи іншою відеокартою. Зверніть увагу, що це публічний об'єкт, тому що його необхідно виділяти ззовні.

Є два ноутбуки – Lenovo і Dell, які мають моделі процесора і дисплея за замовчуванням, а от модель відеокарти потрібно встановити залежно від потреб або бажання.

Dell:

#include "Notebook.h"

class Dell : public Notebook
{
public:
	Dell();
	~Dell();

	virtual void setProcessor();
	virtual void setDisplay();
	virtual void setVideocard();
};  

void Dell::setProcessor()
{
	cout << "Processor AMD A9 is set up." << endl;
}

void Dell::setDisplay()
{
	cout << "Light-emitting diode display is set up." << endl;
}

void Dell::setVideocard()
{
	vcard->setVideocard();
	vcard->runVideocard();
}

Lenovo:

#include "Notebook.h"

class Lenovo : public Notebook
{
public:
	Lenovo();
	~Lenovo();

	virtual void setProcessor();
	virtual void setDisplay();
	virtual void setVideocard();
};

void Lenovo::setProcessor()
{
	cout << "Processor Intel Core i7 is set up." << endl;
}

void Lenovo::setDisplay()
{
	cout << "Liquid crystal display is set up." << endl;
}

void Lenovo::setVideocard()
{
	vcard->setVideocard();
	vcard->runVideocard();
}

Функція setVideocard() викликає відповідну реалізацію відеокарти в залежності якого типу буде об'єкт vcard. Для цього тип відеокарти задається явно.

Використання патерну наступне:

#include "Lenovo.h"
#include "Dell.h"

int main()
{
	cout << "Lenovo:" << endl;
	Notebook* nbook = new Lenovo();		// ноутбук Lenovo
	nbook->setProcessor();				// встановити процесор за замовчуванням
	nbook->setDisplay();				// встановити дисплей за замовчуванням
	Videocard* video = new nvidia920m();// визначити відеокарту nvidia920m
	nbook->vcard = video;				// передати тип відеокарти в ноутбук
	nbook->setVideocard();				// встановити відеокарту nvidia920m

	cout << "\
Dell:" << endl;
	Notebook* nbook2 = new Dell();	// ноутбук Dell
	nbook2->setProcessor();			// встановити процесор за замовчуванням
	nbook2->setDisplay();			// встановити дисплей за замовчуванням
	Videocard* video2 = new amdR5();// визначити відеокарту amdR5
	nbook2->vcard = video2;			// передати тип відеокарти в ноутбук
	nbook2->setVideocard();			// встановити відеокарту amdR5

	cout << "\
Lenovo:" << endl;
	Notebook* nbook3 = new Lenovo();
	nbook3->setProcessor();
	nbook3->setDisplay();
	Videocard* video3 = new amdR5();
	nbook3->vcard = video3;
	nbook3->setVideocard();

    return 0;
}

Результат:

Lenovo:  
Processor Intel Core i7 is set up.  
Liquid crystal display is set up.  
NVIDIA GeForce 920m is set up.  
NVIDIA GeForce 920m is running.  

Dell:  
Processor AMD A9 is set up.  
Light-emitting diode display is set up.  
AMD Radeon R5 is set up.  
AMD Radeon R5 is running.  

Lenovo:  
Processor Intel Core i7 is set up.  
Liquid crystal display is set up.  
AMD Radeon R5 is set up.  
AMD Radeon R5 is running.  
Press any key to continue . . .  

Це дозволяє не створювати додатковий інтерфейс в класі ноутбука, який визначатиме тип відеокарти, а використати вже готовий інтерфейс, що допомагає зменшити втрату продуктивності та підвищує гнучкість коду.

Підсумки

Міст є одним з найпростіших у використанні дизайн-патернів і надає можливість розділити абстракцію класу від його реалізації.

Алгоритм використання:

  1. Створити абстрактний клас, об'єкт нащадка якого виступатиме в ролі моста.
  2. Створити абстрактний клас, який використовує міст для забезпечення різної реалізації.
  3. Встановити тип моста і реалізувати клас.

Вихідний код до статті доступний за посиланням.

Помітили помилку? Повідомте автору, для цього достатньо виділити текст з помилкою та натиснути Ctrl+Enter
Codeguida 4.8K
Приєднався: 10 місяців тому
Коментарі (0)

    Ще немає коментарів

Щоб залишити коментар необхідно авторизуватися.

Вхід / Реєстрація