Jump to content

Шаблон адаптера

(Перенаправлено с Адаптер (программирование) )

В разработке программного обеспечения шаблон адаптера — это шаблон проектирования программного обеспечения (также известный как оболочка , альтернативное имя, общее с шаблоном декоратора ), который позволяет интерфейс существующего класса в качестве другого интерфейса. использовать [ 1 ] Он часто используется для того, чтобы существующие классы могли работать с другими без изменения их исходного кода .

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

Адаптер [ 2 ] Шаблон проектирования — один из двадцати трех известных шаблонов проектирования «Банды четырех» , которые описывают, как решать повторяющиеся проблемы проектирования для разработки гибкого и многократно используемого объектно-ориентированного программного обеспечения, то есть объектов, которые легче реализовать, изменить, протестировать и повторное использование.

Шаблон проектирования адаптера решает такие проблемы, как: [ 3 ]

  • Как можно повторно использовать класс, у которого нет интерфейса, необходимого клиенту?
  • Как классы с несовместимыми интерфейсами могут работать вместе?
  • Как можно предоставить альтернативный интерфейс для класса?

Часто (уже существующий) класс нельзя использовать повторно только потому, что его интерфейс не соответствует интерфейсу, который требуется клиентам.

Шаблон проектирования адаптера описывает, как решить такие проблемы:

  • Определите отдельный adapter класс, который преобразует (несовместимый) интерфейс класса ( adaptee) в другой интерфейс ( target) требуют клиенты.
  • Работайте через adapter для работы с (повторного использования) классами, не имеющими необходимого интерфейса.

Ключевая идея этого шаблона — работать через отдельный adapter который адаптирует интерфейс (уже существующего) класса, не меняя его.

Клиенты не знают, работают ли они с target занятия напрямую или через adapter с классом, который не имеет target интерфейс.

См. также диаграмму классов UML ниже.

Определение

[ редактировать ]

Адаптер позволяет двум несовместимым интерфейсам работать вместе. Это реальное определение адаптера. Интерфейсы могут быть несовместимы, но внутренняя функциональность должна соответствовать потребностям. Шаблон проектирования адаптера позволяет несовместимым в противном случае классам работать вместе путем преобразования интерфейса одного класса в интерфейс, ожидаемый клиентами.

Использование

[ редактировать ]

Адаптер можно использовать, когда оболочка должна соблюдать определенный интерфейс и поддерживать полиморфное поведение. В качестве альтернативы декоратор позволяет добавлять или изменять поведение интерфейса во время выполнения, а фасад используется, когда требуется более легкий или простой интерфейс к базовому объекту. [ 4 ]

Шаблон Намерение
Адаптер или обертка Преобразует один интерфейс в другой, чтобы он соответствовал ожиданиям клиента.
Декоратор Динамически добавляет ответственности к интерфейсу путем переноса исходного кода.
Делегация Поддержка «композиции вместо наследования»
Фасад Обеспечивает упрощенный интерфейс

Структура

[ редактировать ]

Диаграмма классов UML

[ редактировать ]
Пример диаграммы классов UML для шаблона проектирования адаптера. [ 5 ]

На приведенной выше UML классов диаграмме client класс, который требует target интерфейс не может повторно использовать adaptee класс напрямую, потому что его интерфейс не соответствует target интерфейс. Вместо этого client работает через adapter класс, реализующий target интерфейс с точки зрения adaptee:

  • The object adapter способ реализует target интерфейс путем делегирования adaptee объект во время выполнения ( adaptee.specificOperation()).
  • The class adapter способ реализует target интерфейс путем наследования от adaptee класс во время компиляции ( specificOperation()).

Шаблон адаптера объекта

[ редактировать ]

В этом шаблоне адаптера адаптер содержит экземпляр класса, который он обертывает. В этой ситуации адаптер выполняет вызовы экземпляра обернутого объекта .

Шаблон адаптера объекта, выраженный в UML
Шаблон объектного адаптера, выраженный в LePUS3

Шаблон адаптера класса

[ редактировать ]

Этот шаблон адаптера использует несколько полиморфных интерфейсов, реализующих или наследующих как ожидаемый, так и уже существующий интерфейс. Обычно ожидаемый интерфейс создается как чистый класс интерфейса , особенно в таких языках, как Java (до JDK 1.8), которые не поддерживают множественное наследование классов. [ 1 ]

Шаблон адаптера класса, выраженный в UML .
Шаблон адаптера класса, выраженный в LePUS3

Еще одна форма шаблона адаптера времени выполнения.

[ редактировать ]

Мотивация от решения на этапе компиляции

[ редактировать ]

Это желательно для classA поставлять classB с некоторыми данными, давайте предположим, что некоторые String данные. Решение во время компиляции:

classB.setStringData(classA.getStringData());

Однако предположим, что формат строковых данных должен быть изменен. Решением времени компиляции является использование наследования:

public class Format1ClassA extends ClassA {
    @Override
    public String getStringData() {
        return format(toString());
    }
}

и, возможно, создать правильно «форматированный» объект во время выполнения с помощью шаблона фабрики .

Решение для адаптера времени выполнения

[ редактировать ]

Решение с использованием «переходников» происходит следующим образом:

  1. Определите промежуточный интерфейс «поставщика» и напишите реализацию этого интерфейса поставщика, которая обертывает источник данных. ClassA в этом примере и выводит данные в соответствующем формате:
    public interface StringProvider {
        public String getStringData();
    }
    
    public class ClassAFormat1 implements StringProvider {
        private ClassA classA = null;
    
        public ClassAFormat1(final ClassA a) {
            classA = a;
        }
    
        public String getStringData() {
            return format(classA.getStringData());
        }
    
        private String format(final String sourceValue) {
            // Manipulate the source string into a format required 
            // by the object needing the source object's data
            return sourceValue.trim();
        }
    }
    
  2. Напишите класс адаптера, который возвращает конкретную реализацию поставщика:
    public class ClassAFormat1Adapter extends Adapter {
        public Object adapt(final Object anObject) {
            return new ClassAFormat1((ClassA) anObject);
        }
    }
    
  3. Зарегистрируйте adapter с глобальным реестром, так что adapter можно посмотреть во время выполнения:
    AdapterFactory.getInstance().registerAdapter(ClassA.class, ClassAFormat1Adapter.class, "format1");
    
  4. В коде при желании передать данные из ClassA к ClassB, писать:
    Adapter adapter =
        AdapterFactory.getInstance()
            .getAdapterFromTo(ClassA.class, StringProvider.class, "format1");
    StringProvider provider = (StringProvider) adapter.adapt(classA);
    String string = provider.getStringData();
    classB.setStringData(string);
    

    или более кратко:

    classB.setStringData(
        ((StringProvider)
                AdapterFactory.getInstance()
                    .getAdapterFromTo(ClassA.class, StringProvider.class, "format1")
                    .adapt(classA))
            .getStringData());
    
  5. Преимущество можно увидеть в том, что если необходимо передать данные во втором формате, найдите другой адаптер/провайдер:
    Adapter adapter =
        AdapterFactory.getInstance()
            .getAdapterFromTo(ClassA.class, StringProvider.class, "format2");
    
  6. И если требуется вывести данные из ClassA как, скажем, данные изображения в Class C:
    Adapter adapter =
        AdapterFactory.getInstance()
            .getAdapterFromTo(ClassA.class, ImageProvider.class, "format2");
    ImageProvider provider = (ImageProvider) adapter.adapt(classA);
    classC.setImage(provider.getImage());
    
  7. Таким образом, использование адаптеров и провайдеров позволяет использовать несколько «представлений» ClassB и ClassC в ClassA без необходимости изменения иерархии классов. В общем, он допускает механизм произвольных потоков данных между объектами, который можно адаптировать к существующей иерархии объектов.

Реализация шаблона адаптера

[ редактировать ]

При реализации шаблона адаптера для наглядности можно применить имя класса [ClassName]To[Interface]Adapter к реализации провайдера; например, DAOToProviderAdapter. Он должен иметь метод-конструктор с переменной класса адаптера в качестве параметра. Этот параметр будет передан члену экземпляра [ClassName]To[Interface]Adapter. Когда вызывается clientMethod, он будет иметь доступ к экземпляру адаптируемого объекта, что позволяет получить доступ к необходимым данным адаптируемого объекта и выполнить операции над этими данными, которые генерируют желаемый результат.

interface ILightningPhone {
    void recharge();
    void useLightning();
}

interface IMicroUsbPhone {
    void recharge();
    void useMicroUsb();
}

class Iphone implements ILightningPhone {
    private boolean connector;

    @Override
    public void useLightning() {
        connector = true;
        System.out.println("Lightning connected");
    }

    @Override
    public void recharge() {
        if (connector) {
            System.out.println("Recharge started");
            System.out.println("Recharge finished");
        } else {
            System.out.println("Connect Lightning first");
        }
    }
}

class Android implements IMicroUsbPhone {
    private boolean connector;

    @Override
    public void useMicroUsb() {
        connector = true;
        System.out.println("MicroUsb connected");
    }

    @Override
    public void recharge() {
        if (connector) {
            System.out.println("Recharge started");
            System.out.println("Recharge finished");
        } else {
            System.out.println("Connect MicroUsb first");
        }
    }
}
/* exposing the target interface while wrapping source object */
class LightningToMicroUsbAdapter implements IMicroUsbPhone {
    private final ILightningPhone lightningPhone;

    public LightningToMicroUsbAdapter(ILightningPhone lightningPhone) {
        this.lightningPhone = lightningPhone;
    }

    @Override
    public void useMicroUsb() {
        System.out.println("MicroUsb connected");
        lightningPhone.useLightning();
    }

    @Override
    public void recharge() {
        lightningPhone.recharge();
    }
}

public class AdapterDemo {
    static void rechargeMicroUsbPhone(IMicroUsbPhone phone) {
        phone.useMicroUsb();
        phone.recharge();
    }

    static void rechargeLightningPhone(ILightningPhone phone) {
        phone.useLightning();
        phone.recharge();
    }

    public static void main(String[] args) {
        Android android = new Android();
        Iphone iPhone = new Iphone();

        System.out.println("Recharging android with MicroUsb");
        rechargeMicroUsbPhone(android);

        System.out.println("Recharging iPhone with Lightning");
        rechargeLightningPhone(iPhone);

        System.out.println("Recharging iPhone with MicroUsb");
        rechargeMicroUsbPhone(new LightningToMicroUsbAdapter (iPhone));
    }
}

Выход

Recharging android with MicroUsb
MicroUsb connected
Recharge started
Recharge finished
Recharging iPhone with Lightning
Lightning connected
Recharge started
Recharge finished
Recharging iPhone with MicroUsb
MicroUsb connected
Lightning connected
Recharge started
Recharge finished
"""
Adapter pattern example.
"""
from abc import ABCMeta, abstractmethod

NOT_IMPLEMENTED = "You should implement this."

RECHARGE = ["Recharge started.", "Recharge finished."]

POWER_ADAPTERS = {"Android": "MicroUSB", "iPhone": "Lightning"}

CONNECTED = "{} connected."
CONNECT_FIRST = "Connect {} first."

class RechargeTemplate(metaclass=ABCMeta):

    @abstractmethod
    def recharge(self):
        raise NotImplementedError(NOT_IMPLEMENTED)

class FormatIPhone(RechargeTemplate):
    @abstractmethod
    def use_lightning(self):
        raise NotImplementedError(NOT_IMPLEMENTED)

class FormatAndroid(RechargeTemplate):
    @abstractmethod
    def use_micro_usb(self):
        raise NotImplementedError(NOT_IMPLEMENTED)

class IPhone(FormatIPhone):
    __name__ = "iPhone"

    def __init__(self):
        self.connector = False

    def use_lightning(self):
        self.connector = True
        print(CONNECTED.format(POWER_ADAPTERS[self.__name__]))

    def recharge(self):
        if self.connector:
            for state in RECHARGE:
                print(state)
        else:
            print(CONNECT_FIRST.format(POWER_ADAPTERS[self.__name__]))

class Android(FormatAndroid):
    __name__ = "Android"

    def __init__(self):
        self.connector = False

    def use_micro_usb(self):
        self.connector = True
        print(CONNECTED.format(POWER_ADAPTERS[self.__name__]))

    def recharge(self):
        if self.connector:
            for state in RECHARGE:
                print(state)
        else:
            print(CONNECT_FIRST.format(POWER_ADAPTERS[self.__name__]))

class IPhoneAdapter(FormatAndroid):
    def __init__(self, mobile):
        self.mobile = mobile

    def recharge(self):
        self.mobile.recharge()

    def use_micro_usb(self):
        print(CONNECTED.format(POWER_ADAPTERS["Android"]))
        self.mobile.use_lightning()

class AndroidRecharger:
    def __init__(self):
        self.phone = Android()
        self.phone.use_micro_usb()
        self.phone.recharge()

class IPhoneMicroUSBRecharger:
    def __init__(self):
        self.phone = IPhone()
        self.phone_adapter = IPhoneAdapter(self.phone)
        self.phone_adapter.use_micro_usb()
        self.phone_adapter.recharge()

class IPhoneRecharger:
    def __init__(self):
        self.phone = IPhone()
        self.phone.use_lightning()
        self.phone.recharge()

print("Recharging Android with MicroUSB recharger.")
AndroidRecharger()
print()

print("Recharging iPhone with MicroUSB using adapter pattern.")
IPhoneMicroUSBRecharger()
print()

print("Recharging iPhone with iPhone recharger.")
IPhoneRecharger()
public interface ILightningPhone
{
	void ConnectLightning();
	void Recharge();
}

public interface IUsbPhone
{
	void ConnectUsb();
	void Recharge();
}

public sealed class AndroidPhone : IUsbPhone
{
	private bool isConnected;
	
	public void ConnectUsb()
	{
		this.isConnected = true;
		Console.WriteLine("Android phone connected.");
	}

	public void Recharge()
	{
		if (this.isConnected)
		{
			Console.WriteLine("Android phone recharging.");
		}
		else
		{
			Console.WriteLine("Connect the USB cable first.");
		}
	}
}

public sealed class ApplePhone : ILightningPhone
{
	private bool isConnected;
	
	public void ConnectLightning()
	{
		this.isConnected = true;
		Console.WriteLine("Apple phone connected.");
	}

	public void Recharge()
	{
		if (this.isConnected)
		{
			Console.WriteLine("Apple phone recharging.");
		}
		else
		{
			Console.WriteLine("Connect the Lightning cable first.");
		}
	}
}

public sealed class LightningToUsbAdapter : IUsbPhone
{
	private readonly ILightningPhone lightningPhone;
	
	private bool isConnected;
	
	public LightningToUsbAdapter(ILightningPhone lightningPhone)
	{
		this.lightningPhone = lightningPhone;
	}
	
	public void ConnectUsb()
	{
		this.lightningPhone.ConnectLightning();
	}

	public void Recharge()
	{
		this.lightningPhone.Recharge();
	}
}

public void Main()
{
	ILightningPhone applePhone = new ApplePhone();
	IUsbPhone adapterCable = new LightningToUsbAdapter(applePhone);
	adapterCable.ConnectUsb();
	adapterCable.Recharge();
}

Выход:

Apple phone connected.
Adapter cable connected.
Apple phone recharging.


См. также

[ редактировать ]
  1. ^ Перейти обратно: а б Фриман, Эрик; Фриман, Элизабет; Сьерра, Кэти ; Бейтс, Берт (2004). Шаблоны проектирования Head First . О'Рейли Медиа . п. 244. ИСБН  978-0-596-00712-6 . OCLC   809772256 . Архивировано из оригинала (в мягкой обложке) 4 мая 2013 г. Проверено 30 апреля 2013 г.
  2. ^ Гамма, Эрих; Хелм, Ричард; Джонсон, Ральф; Влиссидес, Джон (1994). Шаблоны проектирования: элементы объектно-ориентированного программного обеспечения многократного использования . Эддисон Уэсли . стр. 139 и далее . ISBN  0-201-63361-2 .
  3. ^ «Шаблон проектирования адаптера — проблема, решение и применимость» . w3sDesign.com . Архивировано из оригинала 28 августа 2017 г. Проверено 12 августа 2017 г.
  4. ^ Фриман, Эрик; Фриман, Элизабет; Сьерра, Кэти; Бейтс, Берт (2004). Хендриксон, Майк; Лукидес, Майк (ред.). Шаблоны проектирования Head First (мягкая обложка) . Том. 1. О'Рейли Медиа . стр. 243, 252, 258, 260. ISBN.  978-0-596-00712-6 . Проверено 2 июля 2012 г.
  5. ^ «Шаблон проектирования адаптера — структура и взаимодействие» . w3sDesign.com . Архивировано из оригинала 28 августа 2017 г. Проверено 12 августа 2017 г.
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: 8af263472676c9cb471daa0adbe19adc__1721532600
URL1:https://arc.ask3.ru/arc/aa/8a/dc/8af263472676c9cb471daa0adbe19adc.html
Заголовок, (Title) документа по адресу, URL1:
Adapter pattern - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)