Дизайн-патерни: Адаптер (С++)

2 хв. читання
22 листопада 2017

Породжуючі дизайн-патерни

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

Розглянувши породжуючі дизайн-патерни, слід приступити до наступної групи – структурних патернів.

Структурні патерни описують зв'язки між класами та формують їхню структуру.

Їх є 7:

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

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

Адаптер (Adapter)

Призначення: адаптування функціональності об'єкта для використання в тій чи іншій системі.

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

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

Для цього слід описати ці два стандарти. Наприклад, старий стандарт:

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

	virtual bool connect() = 0;
};

Та новий:

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

	virtual bool connect() = 0;
};

Тоді старий стандарт описуватиме USB 2.0:

#include "OldStandard.h"

class USB_2_0 : public OldStandard
{
public:
	USB_2_0();
	~USB_2_0();

	virtual bool connect();
};

А новий – USB 3.0:

class USB_3_0 :	public NewStandard
{
public:
	USB_3_0();
	~USB_3_0();

	virtual bool connect();
};

Ось як виглядатиме перезавантажена функція connect(), яка під'єднує USB 3.0:

bool USB_3_0::connect()
{
	cout << "USB 3.0 connected to port." << endl;
	return true;
}

На основі цих стандартів створюється адаптер, який, в залежності від версії USB, викликатиме необхідну функцію connect():

#include "USB_2_0.h"
#include "USB_3_0.h"

class USBAdapter : public OldStandard
{
public:
	USBAdapter();
	USBAdapter(NewStandard* _new);
	~USBAdapter();

	virtual bool connect();

private:
	NewStandard* m_new;
};

USBAdapter.cpp

#include "USBAdapter.h"

USBAdapter::USBAdapter()
{
}

USBAdapter::USBAdapter(NewStandard* _new)
{
	m_new = _new;
}

USBAdapter::~USBAdapter()
{
}

bool USBAdapter::connect()
{
	if (m_new->connect())
		return true;
	else
		return false;
}

Зверніть увагу, що клас USBAdapter є похідним від OldStandard. Адже необхідно щоб адаптер, грубо кажучи, «перетворив» новий стандарт на старий, а отже сам адаптер повинен повертати старий стандарт, коли на вхід подається новий.

Конструктором USBAdapter(NewStandard* _new) задається об'єкт нового стандарту й адаптер перезавантажує функцію connect() класу OldStandard, викликаючи тим самим функцію connect() з класу NewStandard. Тобто, якщо в адаптер вставиться новий стандарт, то він під'єднає його як належить, хоча викликатиметься перезавантажена функція старого стандарту, яка у свою чергу викличе функцію для під'єднання нового стандарту.

Отже, як згадувалося, є ноутбук і він може приймати тільки старий стандарт:

#include "USBAdapter.h"

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

	void plugUSB(OldStandard* oldUSB);	// тільки старий формат
};

Функція plugUSB(OldStandard* oldUSB) в якості параметра передає старий стандарт, значить безпосередньо під'єднати USB 3.0 неможливо.

void Notebook::plugUSB(OldStandard* oldUSB)
{
	if (oldUSB->connect())
		cout << "USB connected successfully." << endl;
	else
		cout << "Error. Has not connected." << endl;
} 

Під'єднати USB 2.0 не проблема, а для USB 3.0 проблема вирішується адаптером.

#include "Notebook.h"

int main()
{
	OldStandard* os = new USB_2_0();
	Notebook notebook;
	notebook.plugUSB(os);				// ноутбук підтримує старий стандарт - USB 2.0

	NewStandard* ns = new USB_3_0();
	USBAdapter adapter(ns);				// але не підтримує новий стандарт - USB 3.0
	notebook.plugUSB(&adapter);			// тому під'єднаємо новий стандарт через адаптер

    return 0;
}

При під'єднанні USB 2.0 питань не виникає. У функцію plugUSB() передається параметр os, і функція під'єднала старий стандарт – oldUSB->connect().

Коли під'єднується USB 3.0, створюється об'єкт адаптера, в конструктор якого передається об'єкт нового стандарту – ns. Як згадувалося, клас USBAdapter є похідним від OldStandard, а функція plugUSB() саме приймає об'єкт класу OldStandard. Тому коли передається в функції plugUSB() викликається метод oldUSB->connect(), то викликається перезавантажений метод з класу USBAdapter, котрий в свою чергу викликає метод connect() з класу NewStandard.

USB 2.0 connected to port.
USB connected successfully.
USB 3.0 connected to port.
USB connected successfully.
Press any key to continue . . .

| Результат: |
| -------- |
| USB 2.0 connected to port.  |
| USB connected successfully. |  
| USB 3.0 connected to port.  |
| USB connected successfully. |  
| Press any key to continue . . .  |  

Також адаптер можна використовувати в зворотню або обидві сторони, добавивши необхідний конструктор та перевантаживши функцію.

Підсумки

Адаптер надає можливість для використання об'єкта в не призначеному для нього середовищі.

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

  1. Створити класи, що описують однакове призначення для об'єкта, але є при цьому різного типу та функціональності.
  2. Описати клас-адаптер, що наслідується, як мінімум, від одного класу, до якого необхідно адаптувати об'єкт.
  3. При використанні об'єкта, який не може функціонувати в заданій системі, передати його адаптеру, котрий передається в систему, адаптуючи при цьому переданий об'єкт.

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

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

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

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

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