Понимание шаблона адаптера в JavaScript на реальных примерах.
Здравствуйте, разработчики 👋,
Интеграция различных систем или компонентов — распространенная проблема при разработке программного обеспечения.
Часто это связано с работой с несовместимыми интерфейсами, форматами данных или протоколами.
К счастью, шаблоны проектирования предоставляют элегантные решения для решения этих сложностей интеграции.
В этом сообщении блога мы рассмотрим шаблон адаптера, мощный инструмент в JavaScript, который упрощает интеграцию, выступая в качестве моста между несовместимыми интерфейсами.
Мы углубимся в концепцию шаблона адаптера, поймем его структуру и продемонстрируем его реализацию на практических примерах.
👉 Понимание шаблона адаптера:
Шаблон адаптера — это структурный шаблон проектирования, который обеспечивает связь между двумя несовместимыми интерфейсами, выступая в качестве посредника или моста.
Это позволяет объектам с несовместимыми интерфейсами работать вместе без изменения исходного кода. Шаблон адаптера обеспечивает гибкость, модульность и возможность повторного использования кода, что делает его ценным ресурсом для упрощения задач интеграции.
👉 Структура шаблона адаптера:
Шаблон адаптера состоит из трех основных компонентов:
- Целевой интерфейс. Представляет собой интерфейс, с которым клиентский код должен работать. Он определяет методы и свойства, которые будет использовать клиентский код.
- Адаптируемый: относится к существующему объекту или компоненту, который необходимо интегрировать в клиентский код. Он имеет несовместимый интерфейс, который не может быть напрямую использован клиентом.
- Адаптер: адаптер действует как мост между целевым интерфейсом и адаптируемым. Он реализует целевой интерфейс и внутренне обрабатывает связь и перевод запросов между клиентом и адаптируемым.
💻 Пример 1: Адаптация устаревшего кода
Допустим, у вас есть устаревшая кодовая база, в которой используется проприетарная система ведения журналов с нестандартным интерфейсом. Однако вы хотите переключиться на современную библиотеку журналов со стандартным интерфейсом, например на объект console в JavaScript.
Вот как вы можете использовать шаблон адаптера для бесшовной интеграции новой библиотеки ведения журналов:
// Legacy logging system (Adaptee) class LegacyLogger { logMessage(msg) { // Non-standard logging implementation console.log(`[Legacy] ${msg}`); } } // Modern logging system (Target Interface) class ModernLogger { log(msg) { // Standard logging implementation console.log(msg); } } // Adapter class LegacyToModernLoggerAdapter { constructor() { this.logger = new LegacyLogger(); } log(msg) { this.logger.logMessage(msg); } } // Usage const logger = new ModernLogger(); // New logging system const legacyLoggerAdapter = new LegacyToModernLoggerAdapter(); // Adapter logger.log('This is a modern log'); // Logs using the modern logger legacyLoggerAdapter.log('This is a legacy log'); // Logs using the legacy logger through the adapter
В этом примере LegacyLogger
представляет Adaptee, ModernLogger
представляет целевой интерфейс, а LegacyToModernLoggerAdapter
действует как адаптер.
Адаптер инкапсулирует нестандартный метод logMessage
LegacyLogger
и предоставляет метод журнала, который соответствует стандартному интерфейсу ModernLogger
. С помощью адаптера устаревшая система ведения журналов легко интегрируется с новой библиотекой ведения журналов.
💻 Пример 2. Интеграция платежного шлюза
Предположим, вы создаете приложение для электронной коммерции и вам необходимо интегрировать платежный шлюз для обработки платежей клиентов. Однако разные платежные шлюзы могут иметь свои уникальные интерфейсы и методы обработки транзакций.
Чтобы упростить процесс интеграции и обеспечить согласованный интерфейс для вашего приложения, можно использовать шаблон адаптера:
// Payment Gateway A (Adaptee) class PaymentGatewayA { processPayment(amount) { // Payment processing logic for Gateway A console.log(`Processing payment of $${amount} with Gateway A.`); // Additional implementation specific to Gateway A } } // Payment Gateway B (Adaptee) class PaymentGatewayB { makePayment(amount) { // Payment processing logic for Gateway B console.log(`Making payment of $${amount} with Gateway B.`); // Additional implementation specific to Gateway B } } // Payment Processor Interface (Target Interface) class PaymentProcessor { pay(amount) { throw new Error('pay() method must be implemented.'); } } // Adapter for Payment Gateway A class PaymentGatewayAAdapter extends PaymentProcessor { constructor(gatewayA) { super(); this.gatewayA = gatewayA; } pay(amount) { this.gatewayA.processPayment(amount); } } // Adapter for Payment Gateway B class PaymentGatewayBAdapter extends PaymentProcessor { constructor(gatewayB) { super(); this.gatewayB = gatewayB; } pay(amount) { this.gatewayB.makePayment(amount); } } // Usage const gatewayA = new PaymentGatewayA(); const gatewayB = new PaymentGatewayB(); const adapterA = new PaymentGatewayAAdapter(gatewayA); const adapterB = new PaymentGatewayBAdapter(gatewayB); // Integration with Gateway A const paymentProcessorA = adapterA; paymentProcessorA.pay(100); // Processes payment with Gateway A // Integration with Gateway B const paymentProcessorB = adapterB; paymentProcessorB.pay(200); // Makes payment with Gateway B
В этом примере у нас есть два платежных шлюза, PaymentGatewayA
и PaymentGatewayB
, представляющие Adaptees. Класс PaymentProcessor
представляет целевой интерфейс, который определяет метод оплаты, который клиентский код будет использовать для осуществления платежей.
Классы PaymentGatewayAAdapter
и PaymentGatewayBAdapter
действуют как адаптеры для каждого платежного шлюза соответственно. Они наследуются от класса PaymentProcessor
и реализуют метод оплаты, внутренне вызывая определенные методы обработки платежей соответствующих платежных шлюзов.
Используя шаблон адаптера, приложение электронной коммерции может легко интегрироваться с различными платежными шлюзами с помощью интерфейса PaymentProcessor
. Адаптеры инкапсулируют сложности уникального интерфейса каждого платежного шлюза и обеспечивают согласованный и унифицированный интерфейс для приложения.
💻 Пример 3: API-интеграция
Представьте, что вы создаете погодное приложение, которое использует данные о погоде из нескольких внешних API, каждый из которых имеет свой уникальный формат данных и структуру API.
Чтобы упростить интеграцию этих API и предоставить унифицированный интерфейс для вашего приложения, можно использовать шаблон адаптера:
// External API 1 (Adaptee) class WeatherAPI1 { getWeatherData() { // API-specific implementation and response format return { temperature: 25, humidity: 70, windSpeed: 12, }; } } // External API 2 (Adaptee) class WeatherAPI2 { fetchData() { // API-specific implementation and response format return { temp: 30, humid: 60, wind: 8, }; } } // Unified Weather API (Target Interface) class WeatherAPI { constructor(adapter) { this.adapter = adapter; } getWeather() { const data = this.adapter.fetchData(); // Common data format for the application return { temperature: data.temp || data.temperature, humidity: data.humid || data.humidity, windSpeed: data.wind || data.windSpeed, }; } } // Adapters for the external APIs class API1Adapter { constructor(api) { this.api = api; } fetchData() { const data = this.api.getWeatherData(); return { temperature: data.temperature, humidity: data.humidity, windSpeed: data.windSpeed, }; } } class API2Adapter { constructor(api) { this.api = api; } fetchData() { const data = this.api.fetchData(); return { temperature: data.temp, humidity: data.humid, windSpeed: data.wind, }; } } // Usage const api1 = new WeatherAPI1(); const api2 = new WeatherAPI2(); const api1Adapter = new API1Adapter(api1); const api2Adapter = new API2Adapter(api2); const weatherAPI = new WeatherAPI(api1Adapter); console.log(weatherAPI.getWeather()); // Outputs weather data from API 1 weatherAPI.adapter = api2Adapter; console.log(weatherAPI.getWeather()); // Outputs weather data from API 2
В этом примере у нас есть два внешних API погоды (WeatherAPI1 и WeatherAPI2), которые действуют как Adaptees.
WeatherAPI
представляет целевой интерфейс, а адаптеры API1Adapter и API2Adapter служат адаптерами для каждого API.
WeatherAPI
предоставляет унифицированный метод getWeather
, который внутри использует соответствующий адаптер для извлечения данных из соответствующего API. Используя шаблон адаптера, приложение может легко интегрироваться с несколькими внешними API без необходимости значительных изменений.
Заключение
Шаблон адаптера — ценный инструмент для упрощения задач интеграции в JavaScript.
Выступая в качестве моста между несовместимыми интерфейсами, он позволяет объектам или компонентам работать вместе без изменения их исходного кода. Примеры, приведенные в этом сообщении блога, иллюстрируют, как шаблон адаптера можно применять для адаптации устаревшего кода или интеграции внешних API, предоставляя унифицированный интерфейс и способствуя повторному использованию кода.
Включение шаблона адаптера в ваши проекты JavaScript может значительно повысить гибкость и модульность, делая задачи интеграции более плавными и управляемыми.
Спасибо за прочтение 🙏😇
Советы и рекомендации по веб-разработке | Узнайте о советах и рекомендациях по веб-разработке | Patreon
«Советы и рекомендации по веб-разработке — ваш главный ресурс, посвященный последним тенденциям, практическим советам и инновациям…patreon.com»
Свяжись со мной 👇