Паттерн Adapter (Адаптер) позволяет объектам с несовместимыми интерфейсами работать вместе. Он выступает в роли промежуточного слоя между двумя классами, превращая интерфейс одного класса в интерфейс, ожидаемый другим.
Когда применять Adapter
- Когда нужно использовать существующий класс, но его интерфейс не соответствует требуемому.
- Когда необходимо интегрировать сторонние библиотеки без изменения их исходного кода.
- Когда в проекте присутствуют классы с разными интерфейсами, но схожим функционалом.
PlantUML-диаграмма
// Целевой интерфейс — то, что ожидает клиент
public interface ITarget
{
string GetRequest();
}
// Существующий несовместимый класс
public class Adaptee
{
public string GetSpecificRequest()
{
return "Запрос от несовместимого класса (Adaptee)";
}
}
// Адаптер — преобразует интерфейс Adaptee к интерфейсу ITarget
public class Adapter : ITarget
{
private readonly Adaptee _adaptee;
public Adapter(Adaptee adaptee)
{
_adaptee = adaptee;
}
public string GetRequest()
{
return $"[Адаптировано]: {_adaptee.GetSpecificRequest()}";
}
}
// Клиентский код
class Program
{
static void Main()
{
Adaptee adaptee = new Adaptee();
ITarget target = new Adapter(adaptee);
Console.WriteLine(target.GetRequest());
}
}
// Целевой интерфейс — то, что ожидает клиент
type Target interface {
Request() string
}
// Существующий несовместимый тип
type Adaptee struct{}
func (Adaptee) SpecificRequest() string {
return "Запрос от несовместимого типа (Adaptee)"
}
// Адаптер — приводит Adaptee к интерфейсу Target
type Adapter struct {
adaptee Adaptee
}
func (a Adapter) Request() string {
return "[Адаптировано]: " + a.adaptee.SpecificRequest()
}
func main() {
var target Target = Adapter{adaptee: Adaptee{}}
fmt.Println(target.Request())
}
from typing import Protocol
class Target(Protocol):
def request(self) -> str: ...
class Adaptee:
def specific_request(self) -> str:
return "Запрос от несовместимого класса (Adaptee)"
class Adapter:
def __init__(self, adaptee: Adaptee) -> None:
self._adaptee = adaptee
def request(self) -> str:
return f"[Адаптировано]: {self._adaptee.specific_request()}"
target: Target = Adapter(Adaptee())
print(target.request())
interface Target {
getRequest(): string;
}
class Adaptee {
getSpecificRequest(): string {
return "Запрос от несовместимого класса (Adaptee)";
}
}
class Adapter implements Target {
constructor(private readonly adaptee: Adaptee) {}
getRequest(): string {
return `[Адаптировано]: ${this.adaptee.getSpecificRequest()}`;
}
}
const target: Target = new Adapter(new Adaptee());
console.log(target.getRequest());
interface Target {
String getRequest();
}
class Adaptee {
String getSpecificRequest() {
return "Запрос от несовместимого класса (Adaptee)";
}
}
class Adapter implements Target {
private final Adaptee adaptee;
Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
public String getRequest() {
return "[Адаптировано]: " + adaptee.getSpecificRequest();
}
}
public class Program {
public static void main(String[] args) {
Target target = new Adapter(new Adaptee());
System.out.println(target.getRequest());
}
}
interface Target {
fun getRequest(): String
}
class Adaptee {
fun getSpecificRequest(): String = "Запрос от несовместимого класса (Adaptee)"
}
class Adapter(private val adaptee: Adaptee) : Target {
override fun getRequest(): String = "[Адаптировано]: ${adaptee.getSpecificRequest()}"
}
fun main() {
val target: Target = Adapter(Adaptee())
println(target.getRequest())
}
Плюсы и минусы
| Плюсы | Минусы |
|---|---|
| Позволяет повторно использовать существующий код без изменения | Увеличивает количество классов и усложняет структуру |
| Изолирует клиентский код от изменений в сторонних библиотеках | Может привести к снижению производительности при сложных преобразованиях |
| Следует принципу открытости/закрытости (OCP) | Иногда приводит к дублированию логики адаптации |
Заключение
Adapter — это “переводчик” между несовместимыми интерфейсами. Он делает возможным совместную работу старого и нового кода, сохраняя гибкость и изоляцию компонентов.