“Патерн Вівторка” #22: Адаптер (Adapter)
| Я із деяких причин дуже довго думав над тим який же може бути хороший приклад для Адаптера. Можна приклад коли є операції, які так і називаються ОпераціяА та ОпА, або придумати складний приклад із кучою методів і пропертів в класі що адаптується, але весь цей час в голові у мене крутилася така штукенція, яку ми соваємо у розетку, коли разетка вузька ще СРСР-рівська а ми хочемо запхати шнур для жившення ноутбука із товстою вилкою. Майже така як на картинці збоку, але не настільки жорстока.
Отже у нас є вилка від зарядного пристрою, яка підходить в широкі роз’єми. В одній із квартир у нас усе сучасне, тому NewElectricitySystem має метод MatchWideSocket, яким ми просто можемо скористатися. В іншій квартирі у нас проблемки тому OldElectricitySytem має тільки метод MatchThinSocket. Нажаль ми не можемо собі позволити взяти дрель і роздовбати отвори в розетці – ми купляємо Адаптер, який надає можливість користуватися тою ж функціональністю споживання електричного струму, але із старої системи.
АДАПТЕР
Адаптер – це дизайн патерн, що надає можливість користуватися об’єктом, зміни у який ми не можемо робити, надаючи його функціональність через відомий нашій системі інтерфейс.
// Adaptee
class OldElectricitySystem
{
public string MatchThinSocket()
{
return "220V";
}
}
// широковикористовуваний інтерфейс
// Target
interface INewElectricitySystem
{
string MatchWideSocket();
}
class NewElectricitySystem : INewElectricitySystem
{
public string MatchWideSocket()
{
return "220V";
}
}
// Adapter
class Adapter : INewElectricitySystem
{
private readonly OldElectricitySystem _adaptee;
public Adapter(OldElectricitySystem adaptee)
{
_adaptee = adaptee;
}
// А тут коїться вся магія
// наш адаптер перекладає із того,
// що ми (код) не можемо використати наразі у те що ми можемо
public string MatchWideSocket()
{
return _adaptee.MatchThinSocket();
}
}
// Consumer
class ElectricityConsumer
{
// Зарядний пристрій розуміє тільки нову систему
public static void ChargeNotebook(INewElectricitySystem electricitySystem)
{
Console.WriteLine(electricitySystem.MatchWideSocket());
}
}
public class AdapterDemo
{
public static void Run()
{
// 1) Ми можемо і надалі користувати нашою новою системою
var newElectricitySystem = new NewElectricitySystem();
ElectricityConsumer.ChargeNotebook(newElectricitySystem);
// 2) Ми повинні адаптуватися до старої системи, використовуючи адаптер
var oldElectricitySystem = new OldElectricitySystem();
var adapter = new Adapter(oldElectricitySystem);
ElectricityConsumer.ChargeNotebook(adapter);
}
}
Ще одним ім’ям цього дизайн патерну є Wrapper із-за того що він огортає функціональність якогось об’єкту представлючи її у вигляді іншого інтерфейсу.
Насправді в реалізації не є обов’язковим композиція adaptee, наш клас Adapter міг б реалізовувати два інтерфейси – нової і старої системи. Таким чином одного разу створивши його на базі нової або старої системи, зробивши два конструктори (а чому б і ні), ми б могли використовувати його у два боки.
4 коментарі
Гарний малюнок 🙂 Ну і приклад також 🙂
Дуже дякую.
гарний приклад, все як завжди на висоті, тільки.. ось UML діаграму ще б – був б фул-хаус 🙂
Та я знаю… просто я хочу малювати свої, а на них завжди часу не стає. Дякую. Ще лишилося 3 GoF патерни, думаю що для них таки намалюю, щоб був фул-хаус.