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

Зачем нужен адаптер?

1.8 Middle🔥 171 комментариев
#JavaScript Core

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

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

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

Зачем нужен адаптер?

Адаптер — это паттерн проектирования, который позволяет преобразовать интерфейс одного класса в интерфейс другого, который ожидает клиент. Адаптер создает "мост" между несовместимыми интерфейсами, делая их совместимыми без изменения исходного кода.

Основные проблемы, которые решает адаптер

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

Интеграция с внешними API — при работе с REST API, GraphQL или других внешних сервисов их ответы часто имеют структуру, отличную от той, которую использует приложение.

Переиспользование кода — позволяет использовать полезный код, который нельзя напрямую изменить (например, библиотека третьей стороны).

Практические примеры в Frontend

Пример 1: Адаптер для API

// API возвращает такую структуру
const apiResponse = {
  user_id: 123,
  first_name: "John",
  last_name: "Doe",
  email_address: "john@example.com"
};

// Но приложение ожидает такую
interface User {
  id: number;
  firstName: string;
  lastName: string;
  email: string;
}

// Адаптер преобразует API-ответ в нужный формат
const adaptUserFromAPI = (apiData: any): User => {
  return {
    id: apiData.user_id,
    firstName: apiData.first_name,
    lastName: apiData.last_name,
    email: apiData.email_address
  };
};

const user: User = adaptUserFromAPI(apiResponse);

Пример 2: Адаптер для работы с датами

// Разные форматы дат из разных API
const momentDate = moment("2024-01-15");
const dateObject = new Date("2024-01-15");

// Привести все к единому формату
interface AppDate {
  timestamp: number;
  iso: string;
  formatted: string;
}

const adaptDate = (date: any): AppDate => {
  const dateObj = date instanceof Date ? date : new Date(date);
  return {
    timestamp: dateObj.getTime(),
    iso: dateObj.toISOString(),
    formatted: dateObj.toLocaleDateString("ru-RU")
  };
};

Пример 3: Адаптер для разных платежных систем

// Различные платежные API имеют разные интерфейсы
interface PaymentProvider {
  processPayment(amount: number, currency: string): Promise<Transaction>;
}

// Адаптер для Stripe
class StripeAdapter implements PaymentProvider {
  constructor(private stripeAPI: any) {}
  
  async processPayment(amount: number, currency: string) {
    const result = await this.stripeAPI.charges.create({
      amount: amount * 100, // Stripe работает в центах
      currency: currency.toLowerCase(),
      source: "tok_visa"
    });
    return {
      transactionId: result.id,
      status: result.status === "succeeded" ? "success" : "failed"
    };
  }
}

// Адаптер для PayPal
class PayPalAdapter implements PaymentProvider {
  constructor(private paypalAPI: any) {}
  
  async processPayment(amount: number, currency: string) {
    const result = await this.paypalAPI.executePayment({
      value: amount.toString(),
      currency_code: currency
    });
    return {
      transactionId: result.id,
      status: result.state === "approved" ? "success" : "failed"
    };
  }
}

Адаптер в React

// Кастомный хук как адаптер
function useApiUser(userId: number) {
  const [user, setUser] = useState<User | null>(null);
  
  useEffect(() => {
    fetch(`/api/users/${userId}`)
      .then(res => res.json())
      .then(apiData => {
        // Адаптируем API-ответ к формату приложения
        const adaptedUser: User = {
          id: apiData.user_id,
          firstName: apiData.first_name,
          lastName: apiData.last_name,
          email: apiData.email_address
        };
        setUser(adaptedUser);
      });
  }, [userId]);
  
  return user;
}

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

  1. Разделение ответственности — логика трансформации отделена от основного кода
  2. Переиспользуемость — адаптер можно использовать в разных местах
  3. Тестируемость — легко тестировать преобразования отдельно
  4. Гибкость — легко менять реализацию без изменения кода, который его использует
  5. Инкапсуляция — скрывает сложность преобразования внешних интерфейсов

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

  • Нужно интегрировать библиотеку с несовместимым интерфейсом
  • Работаешь с API, возвращающим данные в неудобном формате
  • Нужно унифицировать работу с несколькими похожими компонентами
  • Хочешь изолировать код от изменений во внешних зависимостях

Адаптер — важный паттерн для создания гибких и поддерживаемых приложений, позволяя легко работать с несовместимыми интерфейсами и внешними API.