← Назад к вопросам

Как адаптер связан с Adaptive паттерном ООП?

2.0 Middle🔥 141 комментариев
#Архитектура и паттерны

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как адаптер связан с Adaptive паттерном ООП

Adapter (Адаптер) в ООП - это один из самых практичных паттернов проектирования. Его связь с реальной жизнью интуитивна: как электрический адаптер позволяет подключить устройство с одним типом разъёма к розетке с другим, так и паттерн Adapter позволяет несовместимым интерфейсам работать вместе.

Суть паттерна Adapter

Назначение: превратить интерфейс класса в другой интерфейс, который ожидается клиентом. Адаптер позволяет классам с несовместимыми интерфейсами сотрудничать.

Когда использовать

  • Интеграция старого кода с новым
  • Работа с внешними библиотеками
  • Приведение разных API к единому интерфейсу
  • Подключение компонентов с разными контрактами

Структура паттерна

Четыре участника:

  1. Target - интерфейс, который ожидает клиент
  2. Adaptee - существующий класс с несовместимым интерфейсом
  3. Adapter - класс-посредник, конвертирующий интерфейсы
  4. Client - код, использующий Target интерфейс

Пример на JavaScript

// Target interface (ожидаемый интерфейс)
interface MediaPlayer {
  play(file: string): void;
  pause(): void;
  stop(): void;
}

// Adaptee (существующий класс с другим интерфейсом)
class VlcPlayer {
  playFile(path: string) {
    console.log(`Playing VLC: ${path}`);
  }
  
  pausePlayback() {
    console.log('VLC paused');
  }
  
  stopPlayback() {
    console.log('VLC stopped');
  }
}

// Adapter (посредник между интерфейсами)
class VlcPlayerAdapter implements MediaPlayer {
  private vlcPlayer: VlcPlayer;
  
  constructor() {
    this.vlcPlayer = new VlcPlayer();
  }
  
  play(file: string): void {
    this.vlcPlayer.playFile(file);
  }
  
  pause(): void {
    this.vlcPlayer.pausePlayback();
  }
  
  stop(): void {
    this.vlcPlayer.stopPlayback();
  }
}

// Client
class AudioApp {
  constructor(private player: MediaPlayer) {}
  
  playMusic(song: string) {
    this.player.play(song);
    this.player.pause();
    this.player.stop();
  }
}

// Использование
const adapter = new VlcPlayerAdapter();
const app = new AudioApp(adapter);
app.playMusic('song.mp3');

Frontend примеры

Пример 1: Адаптация фетч API

// API клиент ожидает определённый интерфейс
class ApiClient {
  async request(url: string, options: object) {
    // Использует fetch
    return fetch(url, options);
  }
}

// Но у нас есть axios с другим интерфейсом
import axios from 'axios';

// Создаём адаптер
class AxiosAdapter implements RequestAdapter {
  async request(url: string, options: object) {
    const response = await axios(url, options);
    return response.data;
  }
}

// Теперь axios работает как fetch
const adapter = new AxiosAdapter();
const client = new ApiClient(); // работает с адаптером

Пример 2: Адаптация UI компонентов

// Новый компонент с новым интерфейсом
interface ButtonComponent {
  onClick: (callback: Function) => void;
  setLabel: (text: string) => void;
  render: () => JSX.Element;
}

// Старый компонент с другим интерфейсом
const OldButton = (props: { onPress?: Function; text?: string }) => (
  <button onClick={() => props.onPress?.()}>
    {props.text}
  </button>
);

// Адаптер для совместимости
const OldButtonAdapter = (props: ButtonComponent) => (
  <OldButton
    onPress={() => props.onClick(() => {})}
    text={props.label}
  />
);

Пример 3: Адаптация хуков

// Старый хук с callback-ами
function useOldData(callback: (data: any) => void) {
  useEffect(() => {
    fetchData().then(data => callback(data));
  }, []);
}

// Новый интерфейс с промисами
function useData(): Promise<any> {
  return fetch('/api/data').then(r => r.json());
}

// Адаптер
function useDataAdapter() {
  const [data, setData] = useState(null);
  
  useOldData((newData) => {
    setData(newData);
  });
  
  return data;
}

Два типа реализации

1. Class Adapter (через наследование)

class Adapter extends Adaptee implements Target {
  method1() {
    return this.adapteeMethod();
  }
}

2. Object Adapter (через композицию)

class Adapter implements Target {
  private adaptee: Adaptee;
  
  method1() {
    return this.adaptee.adapteeMethod();
  }
}

Композиция предпочтительнее, так как более гибкая.

Связь с Adaptive паттерном

Нет формального паттерна "Adaptive" в классической книге Gang of Four. Однако:

  • Adapter - это паттерн для адаптации существующего кода
  • Strategy - адаптирует алгоритмы во время выполнения
  • Decorator - адаптирует функциональность объекта
  • Bridge - адаптирует абстракцию от реализации

Все эти паттерны решают проблему адаптации - приведения несовместимого кода к единому интерфейсу.

Преимущества

  • Разделение ответственности
  • Переиспользование старого кода
  • Избегаем изменения существующего кода
  • Гибкость в интеграции разных компонентов

Недостатки

  • Дополнительная сложность
  • Избыточный код если простая адаптация
  • Может скрыть реальные проблемы дизайна

Выводы

Adapter - это мощный паттерн для работы с несовместимыми интерфейсами. Во Frontend он особенно полезен при интеграции разных библиотек, миграции кода и создании абстракций над внешними API.

Как адаптер связан с Adaptive паттерном ООП? | PrepBro