Шаблон проектирования адаптера
Это специальный объект, который преобразует интерфейс одного объекта так, чтобы его мог понять другой объект.
Адаптер преобразует интерфейс класса в другой интерфейс, ожидаемый клиентами. Адаптер позволяет классам работать вместе, что в противном случае было бы невозможно из-за несовместимых интерфейсов.
Используйте шаблон, если вы хотите повторно использовать несколько существующих подклассов, в которых отсутствуют некоторые общие функции, которые нельзя добавить в суперкласс.
Как работает адаптер
- Адаптер получает интерфейс, совместимый с одним из существующих объектов.
- Используя этот интерфейс, существующий объект может безопасно вызывать методы адаптера.
- При получении вызова адаптер передает запрос второму объекту, но в формате и порядке, ожидаемом вторым объектом.
Адаптер объекта
- Клиент — это класс, содержащий существующую бизнес-логику программы.
- Клиентский интерфейс описывает протокол, которому должны следовать другие классы, чтобы иметь возможность взаимодействовать с клиентским кодом.
- Служба – это полезный класс (обычно сторонний или устаревший). Клиент не может использовать этот класс напрямую, потому что у него несовместимый интерфейс.
- Адаптер — это класс, способный работать как с клиентом, так и со службой: он реализует клиентский интерфейс, оборачивая при этом объект службы. Адаптер получает вызовы от клиента через интерфейс адаптера и преобразовывает их в вызовы обернутого объекта службы в понятном ему формате.
Адаптер класса
Ему не нужно оборачивать какие-либо объекты, потому что он наследует поведение как клиента, так и службы. Адаптация происходит в переопределенных методах. Полученный адаптер можно использовать вместо существующего клиентского класса.
Осуществлять
- Убедитесь, что у вас есть как минимум два класса с несовместимыми интерфейсами.
- Объявите клиентский интерфейс и опишите, как клиенты взаимодействуют со службой.
- Создайте класс адаптера и заставьте его следовать клиентскому интерфейсу. Оставьте пока все методы пустыми.
- Добавьте в класс адаптера поле для хранения ссылки на объект службы.
- Один за другим реализуйте все методы клиентского интерфейса в классе адаптера.
- Клиенты должны использовать адаптер через клиентский интерфейс. Это позволит вам изменять или расширять адаптеры, не затрагивая клиентский код.
Проблема: рабочее время сотрудника
У нас есть объект для сотрудника, который рассчитывает отработанное время в час, также у каждого сотрудника должен быть контракт, который рассчитывает отработанное время в день. каждый сотрудник работает 8 часов в день, поэтому, если сотрудник отработал 2 дня, он вычислил => 2 * 8 = 16 часов, отработанных за 2 дня.
- Мы не добавляем новую функцию в класс Employee из-за принципа открытости-закрытости (OCP)
interface IEmployee { work_in_hour(): number; } class Employee implements IEmployee { public hour_worked: number; constructor(hour_worked: number) { this.hour_worked = hour_worked; } work_in_hour(): number { return this.hour_worked; } } interface IContractor { work_in_day(): number; } class Contractor implements IContractor { public day_worked: number; constructor(day_worked: number) { this.day_worked = day_worked; } work_in_day(): number { return this.day_worked; } } class ContractorAdapter implements IEmployee { private contractor: IContractor; constructor(contractor: IContractor) { this.contractor = contractor; } work_in_hour() { return this.contractor.work_in_day() * 8; } } class EmployeeAdapter implements IContractor { private employee: IEmployee; constructor(employee: IEmployee) { this.employee = employee; } work_in_day() { return this.employee.work_in_hour() / 8; } } let employee_1 = new Employee(200); let contractor_1 = new Contractor(19); // 19 day = 152 hours const to_hour = new ContractorAdapter(contractor_1).work_in_hour(); // 200 hours = 25 days const to_day = new EmployeeAdapter(employee_1).work_in_day();
Плюсы
- Принцип единой ответственности. Вы можете отделить код интерфейса или преобразования данных от основной бизнес-логики программы.
- Принцип открытия/закрытия. Вы можете вводить в программу новые типы адаптеров, не ломая существующий клиентский код, при условии, что они работают с адаптерами через клиентский интерфейс.
Минусы
- Общая сложность кода увеличивается, потому что вам нужно ввести набор новых интерфейсов и классов. Иногда проще просто изменить класс сервиса, чтобы он соответствовал остальному коду.