Адаптер (шаблон проектування)

Матеріал з Вікіпедії — вільної енциклопедії.
Перейти до: навігація, пошук

Адаптер, Adapter — структурний шаблон проектування, призначений для організації використання функцій об'єкта, недоступного для модифікації, через спеціально створений інтерфейс.

Призначення[ред.ред. код]

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

Застосування[ред.ред. код]

Адаптер передбачає створення класу-оболонки з необхідним інтерфейсом.

Структура[ред.ред. код]

UML діаграма, що ілюструє структуру шаблону проектування Адаптер (з використанням множинного наслідування)

Учасники[ред.ред. код]

Клас Adapter приводить інтерфейс класу Adaptee у відповідність з інтерфейсом класу Target (спадкоємцем якого є Adapter). Це дозволяє об'єктові Client використовувати об'єкт Adaptee так, немов він є екземпляром класу Target.

Наслідки[ред.ред. код]

Шаблон Адаптер дозволяє включати вже існуючі об'єкти в нові об'єктні структури, незалежно від відмінностей в їхніх інтерфейсах.

Реалізація[ред.ред. код]

Інтерфейс класу Adaptee, тобто того, який адаптується, приводиться у відповідність з новими вимогами класу Target, а виклики його методів перетворяться у виклики методів класу Target.

Шаблон Адаптер для адаптації інтерфейсу методу/ів Adaptee до інтерфейсу Target в Adapter можна реалізувати як мінімум двома способами: використовуючи композицію+успадкування (Адаптер об'єкта), або використовуючи множинне успадкування (Aдаптер класу).

  • Адаптер об'єкта: Adapter наслідує інтерфейс від Target (успадкування) та містить примірник (здебільшого як вказівник) класу Adaptee (композиція) і делегує виклики своїх методів (які збігаються з інтерфейсом Target) до Adaptee
  • Адаптер класу: Adapter наслідує інтерфейси обох класів Target та Adaptee (множинне успадкування). В ООП-мовах, які не підтримують множинне успадкування, реалізація цього варіанту адаптера дещо складніша (наприклад в Java за допомогою інтерфейсів).

Приклад С++ (Адаптер класу)[ред.ред. код]

#include <string>
#include <iostream>

// Target
class CShape
{
public:
	virtual ~CShape() {};

	virtual void Draw() {
		std::cout << "Rectangle" << std::endl; 
	};
};

// Adaptee
class CTextViewer
{
public:
	CTextViewer() {};
	virtual ~CTextViewer() {};

	void DrawText() {
		std::cout << "Text" << std::endl; 
	};
};

// Adapter
class CTextShape: public CShape, protected CTextViewer
{
public:
	CTextShape() {};
	virtual ~CTextShape() {};

	virtual void Draw() {
		DrawText(); // Call Adaptee function
	};
};

// Client
void DrawObject(CShape* p)
{
	p->Draw();
}

int main()
{
	// Create adapter and draw a object
	CShape* obj = new CTextShape();
	DrawObject(obj);
	delete obj;

	return 0;
}

Зауваження і коментарі[ред.ред. код]

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

Більш прийнятним є адаптер об'єкта, в якому використовується композиція+успадкування, оскільки це більш відповідає правилу "надавайте перевагу композиції, а не успадкуванню". Цей адаптер можна використовувати тільки односторонньо - як заміну для Target. Однак, у випадку, коли ми створюємо двосторонній адаптер, або ж адаптер, який адаптує одночасно кілька Adaptee класів, слід надавати перевагу шаблону адаптера класу. Також адаптер класу дозволяє більш ефективно використовувати вже реалізований код з Target та Adaptee. Однак недоліки адаптера класу випливають з множинного успадкування, коли зміни в деяких базових класах викликають непередбачливі зміни в похідних, а особливо, коли це відбувається одночасно в кількох успадкованих адаптером класах.

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

Відомі застосування[ред.ред. код]

Типовим прикладом використання шаблону Адаптер можна назвати створення класів, що приводять до єдиного інтерфейсу функції мови PHP що забезпечують доступ до різних СУБД[1].

Примітки[ред.ред. код]

  1. В мові PHP доступ до СУБД реалізований у вигляді набору функцій, для кожної СУБД вони мають різні найменування і, іноді, різний набір використовуваних параметрів, що приводить до значних проблем при переході з однією СУБД на іншу, якщо такий перехід наперед не забезпечений використанням шаблону Адаптер.

Джерела[ред.ред. код]

Література[ред.ред. код]

Алан Шаллоуей, Джеймс Р. Тротт Шаблоны проектирования. Новый подход к объектно-ориентированному анализу и проектированию = Design Patterns Explained: A New Perspective on Object-Oriented Design. — М. : «Вильямс», 2002. — 288 с. — ISBN 0-201-71594-5.