По своей сути паттерн Адаптер очень прост. Его реализация заключается в создании обёртки над объектом, имплементирующей нужный интерфейс. Имлементация методов интерфейса, соответсвенно, должна выглядеть как преобразование аргументов и вызов методов у оборачиваемого объекта.
Target - целевой интерфейс, который имплементирует класс обёртка
Adaptee - оборачиваемый объект
Adapter - объект-обёртка
Паттерн Адаптер можно использовать как посредника для достижения полиморфизма между типами не находящимися в одной иерархии. Он является склейкой между объектами имеющими различные интерфейсы.
Применение адаптера может быть полезно в ситуациях когда код объединяемых типов не может быть изменён, либо когда его изменения несут за собой сильные риски.
public class SqlServerLogSaver
{
public void Save(string message, DateTime timeStamp, int severity) { ... }
}
public class ElasticLogSaver
{
public void Save(ElasticLogMessage message);
}
public interface ILogSaver
{
void Save(LogEntry entry);
}
public SqlServerLogSaverAdapter : ILogSaver
{
private readonly SqlServerLogSaver _saver;
public void Save(LogEntry entry)
{
_saver.Save(entry.Message, entry.DateTime, entry.Severity.AsInteger());
}
}
public ElasticLogSaverAdapter : ILogSaver
{
private readonly ElasticLogSaver _saver;
public void Save(LogEntry entry)
{
_saver.Save(entry.AsElasticLogMessage());
}
}
Паттерн адаптер может быть использован для локализации рефакторинга. Предположим вы проводите рефакторинг кода, который требует изменение интерфейса используемых объектов (добавление асинхронности в нашу систему логирования). На первый взгляд, это приведёт к тому, что придётся изменять как код, использующий старые интерфейсы (на использование новых), так и код, реализующий старые интерфейсы (на реализацию новых).
Изменения можно локализовать путём добавления адаптера, из старого интерфейса в новый, соответсвенно рефакторинг можно разбить на два шага, изменение использований, изменение реализаций, после которых добавленные адаптеры можно будет удалить за ненадобностью.
public IAsyncLogSaver
{
Task SaveAsync(SaveAsync entry);
}
public AsyncLogSaverAdapter : IAsyncLogSaver
{
private readonly ILogSaver _saver;
public Task SaveAsync(SaveAsync entry)
{
_saver.Save(entry);
return Task.CompletedTask;
}
}