
type
//target interface
IEuroSocket = interface
function GetPower: string;
end;
//existing class with a wrong interface
TUsSocket = class
public
function GetUsPower: string;
end;
//class adapter: inherits the adaptee
//and implements the target
TSocketAdapter = class(TUsSocket,
IEuroSocket)
private
FRefCount: Integer;
public
function GetPower: string;
function QueryInterface(const IID: TGUID;
out Obj): HResult; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
end;
function TUsSocket.GetUsPower: string;
begin
Result := '110V';
end;
function TSocketAdapter.GetPower: string;
begin
Result := GetUsPower + ' as 220V';
end;
function TSocketAdapter.QueryInterface(
const IID: TGUID; out Obj): HResult;
begin
if GetInterface(IID, Obj) then
Result := 0
else
Result := E_NOINTERFACE;
end;
function TSocketAdapter._AddRef: Integer;
begin
Inc(FRefCount);
Result := FRefCount;
end;
function TSocketAdapter._Release: Integer;
begin
Dec(FRefCount);
Result := FRefCount;
end;
var
Socket: IEuroSocket;
begin
Socket := TSocketAdapter.Create;
WriteLn(Socket.GetPower);
//110V as 220V
end.
Преобразует интерфейс класса в другой интерфейс, ожидаемый клиентами. Обеспечивает совместную работу классов, которая была бы невозможна без данного паттерна из-за несовместимости интерфейсов.Read moreЗадача. Программа читает текст из любого источника через один метод. Готовый библиотечный класс хранит строки текста и умеет их склеивать, но метод у него называется иначе. Библиотеку изменить нельзя. Переписывать весь код, который вызывает ожидаемый метод, тоже не хочется. Идея. Адаптер подгоняет существующий класс под интерфейс, которого ждёт клиент. Такой класс называют адаптируемым, а нужный клиенту интерфейс - целевым. В этом варианте адаптер наследует адаптируемый класс и вдобавок реализует целевой интерфейс. Его целевой метод просто вызывает унаследованный, иногда с небольшим преобразованием. Поэтому адаптер сам по себе - адаптируемый класс со всеми его методами. Для сравнения: адаптер через композицию хранит адаптируемый объект, а не наследует его класс. Как читать пример. Адаптируемый класс уже делает нужную работу, но метод у него называется иначе. Целевой интерфейс объявляет метод, которого ждёт клиент. Адаптер наследует адаптируемый класс и добавляет целевой метод, который вызывает унаследованный. Объект здесь один: адаптер и есть адаптируемый объект. В большинстве языков клиент наполняет его собственными методами адаптируемого класса, а результат читает через целевой метод. Языки без наследования классов его имитируют: встраивают адаптируемый объект или добавляют целевой метод прямо в тип адаптируемого. Когда применять. Адаптер класса нужен, когда подгоняется один известный класс и заодно нужны его остальные методы. Он не годится, если подгоняемый объект уже существует или может оказаться подклассом адаптируемого. Адаптер класса - это всегда новый объект одного жёстко заданного класса, поэтому такие объекты он подогнать не может. Частая ошибка. Забыть, что адаптер открывает наружу все методы адаптируемого класса. Клиенты начинают вызывать их напрямую, и целевой интерфейс больше не скрывает адаптируемый. |