Теория 📔
July 4, 2024

Паттерн "Адаптер" в Angular

Паттерн Адаптер (Adapter Pattern) — это структурный паттерн проектирования, который позволяет объектам с несовместимыми интерфейсами работать вместе. Адаптер выступает в роли посредника, который преобразует интерфейс одного класса в интерфейс, ожидаемый клиентом.

Основные концепции

  1. Целевой интерфейс (Target): Интерфейс, который ожидает клиент.
  2. Клиент (Client): Объект, который использует целевой интерфейс.
  3. Адаптируемый (Adaptee): Класс с несовместимым интерфейсом, который нужно адаптировать.
  4. Адаптер (Adapter): Класс, который преобразует интерфейс адаптируемого класса в целевой интерфейс.

Пример использования

Предположим, у нас есть старая библиотека для работы с аутентификацией, но интерфейс этой библиотеки не соответствует тому, что требуется нашему Angular приложению. Мы хотим использовать паттерн Адаптер, чтобы интегрировать эту библиотеку в наше приложение.

Шаги

  1. Создадим целевой интерфейс (Target)
  2. Адаптируемый класс (Adaptee)
  3. Адаптер (Adapter)
  4. .Используем Адаптер в Angular компоненте (Client)

1. Целевой интерфейс (Target)

Целевой интерфейс описывает методы, которые должны быть реализованы для работы с аутентификацией.

// auth.service.ts
export interface AuthService {
    login(username: string, password: string): Promise<boolean>;
    logout(): void;
    isAuthenticated(): boolean;
}

2. Адаптируемый класс (Adaptee)

Адаптируемый класс представляет собой старую библиотеку, которую нужно адаптировать.

// legacy-auth.ts
export class LegacyAuth {
    signIn(user: string, pass: string): boolean {
        console.log('Using legacy auth system to sign in...');
        return user === 'admin' && pass === 'admin'; // Simplified example
    }

    signOut(): void {
        console.log('Using legacy auth system to sign out...');
    }

    checkAuth(): boolean {
        console.log('Using legacy auth system to check authentication...');
        return true; // Simplified example
    }
}

3. Адаптер (Adapter)

Адаптер реализует целевой интерфейс и использует адаптируемый класс для выполнения работы.

// auth-adapter.service.ts
import { Injectable } from '@angular/core';
import { AuthService } from './auth.service';
import { LegacyAuth } from './legacy-auth';

@Injectable({
    providedIn: 'root'
})
export class AuthAdapterService implements AuthService {
    private legacyAuth: LegacyAuth;

    constructor() {
        this.legacyAuth = new LegacyAuth();
    }

    async login(username: string, password: string): Promise<boolean> {
        return new Promise((resolve) => {
            const result = this.legacyAuth.signIn(username, password);
            resolve(result);
        });
    }

    logout(): void {
        this.legacyAuth.signOut();
    }

    isAuthenticated(): boolean {
        return this.legacyAuth.checkAuth();
    }
}

Использование адаптера в Angular компоненте (Client)

Теперь мы можем использовать наш адаптер в Angular компоненте для работы с аутентификацией.

// app.component.ts
import { Component } from '@angular/core';
import { AuthService } from './auth.service';
import { AuthAdapterService } from './auth-adapter.service';

@Component({
    selector: 'app-root',
    template: `
    <div>
        <button (click)="login()">Login</button>
        <button (click)="logout()">Logout</button>
        <p *ngIf="isAuthenticated()">Authenticated</p>
        <p *ngIf="!isAuthenticated()">Not Authenticated</p>
    </div>
    `
})
export class AppComponent {
    constructor(private authService: AuthAdapterService) { }

    async login() {
        const success = await this.authService.login('admin', 'admin');
        if (success) {
            console.log('Login successful');
        } else {
            console.log('Login failed');
        }
    }

    logout() {
        this.authService.logout();
        console.log('Logged out');
    }

    isAuthenticated(): boolean {
        return this.authService.isAuthenticated();
    }
}

Пояснение

  1. Целевой интерфейс (AuthService) описывает методы, необходимые для работы с аутентификацией.
  2. Адаптируемый класс (LegacyAuth) представляет собой старую библиотеку с несовместимым интерфейсом.
  3. Адаптер (AuthAdapterService) реализует целевой интерфейс и использует методы старой библиотеки для выполнения задач аутентификации.
  4. Клиент (AppComponent) использует адаптер для работы с аутентификацией, не зная о существовании старой библиотеки.