Структурные паттерны: Адаптер (Adapter) C#
Назначение:
Преобразует интерфейс одного класса в интерфейс другого, который ожидают клиенты. Адаптер делает возможной совместную работу классов с несовместимыми интерфейсами.
Когда следует использовать Адаптер?
-
Когда необходимо использовать имеющийся класс, но его интерфейс не соответствует потребностям бизнесс логики.
-
Когда надо использовать уже существующий класс совместно с другими классами, интерфейсы которых не совместимы.
Схема примера использования паттерна "Adapter" из реальной жизни:
UML схема паттерна адаптер:
Участники
-
Target: представляет объекты, которые используются клиентом
-
Client: использует объекты Target для реализации своих задач
-
Adaptee: представляет адаптируемый класс, который мы хотели бы использовать у клиента вместо объектов Target
-
Adapter: собственно адаптер, который позволяет работать с объектами Adaptee как с объектами Target.
Реализация шаблона адаптер на C#
using System;
namespace DoFactory.GangOfFour.Adapter.Structural
{
/// <summary>
/// MainApp startup class for Structural
/// Adapter Design Pattern.
/// </summary>
class MainApp
{
/// <summary>
/// Entry point into console application.
/// </summary>
static void Main()
{
// Create adapter and place a request
Target target = new Adapter();
target.Request();
// Wait for user
Console.ReadKey();
}
}
/// <summary>
/// The 'Target' class
/// </summary>
class Target
{
public virtual void Request()
{
Console.WriteLine("Called Target Request()");
}
}
/// <summary>
/// The 'Adapter' class
/// </summary>
class Adapter : Target
{
private Adaptee _adaptee = new Adaptee();
public override void Request()
{
// Possibly do some other work
// and then call SpecificRequest
_adaptee.SpecificRequest();
}
}
/// <summary>
/// The 'Adaptee' class
/// </summary>
class Adaptee
{
public void SpecificRequest()
{
Console.WriteLine("Called SpecificRequest()");
}
}
}
Output
Called SpecificRequest()
Обсуждение паттерна «Адаптер»
Адаптер является одним из тех паттернов проектирования, которые мы используем, почти не задумываясь. Диаграмма классов этого паттерна настолько общая, что практически любую композицию объектов можно считать примером использования адаптеров.
Адаптер классов и объектов «Бандой четырех» были описаны два вида адаптеров — адаптеры классов и адаптеры объектов. Ранее был рассмотрен пример адаптера объектов. В этом случае создается новый класс, который реализует требуемый интерфейс и делегирует всю работу адаптируемому объекту, хранящемуся в виде закрытого поля.
Применимость
Адаптер позволяет использовать существующие типы в новом контексте
- Повторное использование чужого кода. В некоторых случаях у нас уже есть код, который решает нужную задачу, но его интерфейс не подходит для текущего приложения. Вместо изменения кода библиотеки можно создать слой адаптеров.
- Адаптивный рефакторинг. Адаптеры позволяют плавно изменять существующую функциональность путем выделения нового «правильного» интерфейса, но с использованием старой проверенной функциональности.
Примеры в .NET Framework
- TextReader/TextWriter — адаптеры над классами Stream для чтения/записи текстовых данных в потоки ввода/вывода.
- BinaryReader/BinaryWriter — аналогичные адаптеры для работы с бинарными данными потоков ввода/вывода.
- ReadonlyCollection — адаптирует произвольный список (IList) к коллекции только для чтения (IReadonlyCollection)
- Любая реализация LINQ-провайдера (интерфейса IQueryProvider) служит своеобразным адаптером, поскольку подстраивает классы для работы с внешним источником данных к интерфейсу IQueryProvider.