Adapter (inheritance)

Design patterns / Structural patterns
image

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.


Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.
Read more

The problem. Your program reads text from any source through one method. A ready library class keeps lines of text and can join them, but through a method with another name. You cannot change the library. You also do not want to change all the code that calls the method it expects.

The idea. An adapter makes an existing class, the adaptee, fit the interface that the client expects, the target. In this version the adapter is a subclass of the adaptee and also implements the target. Its target method only calls the inherited method, sometimes with a small conversion. So the adapter is itself an adaptee and keeps all its methods. Compare the adapter by composition: it holds an adaptee instead of extending it.

How to read the example. The adaptee already does the work, but under another method. The target declares the method that the client expects. The adapter extends the adaptee and adds the target method, which calls the inherited one. There is only one object: the adapter is the adaptee. In most languages the client fills it through the adaptee's own methods and reads the result through the target method. Languages without class inheritance imitate it: they embed the adaptee, or they add the target method to the adaptee's own type.

When to use it. Use a class adapter when you adapt one known class and also need its other methods. Do not use it when the object to adapt already exists, or when it may belong to a subclass of the adaptee. A class adapter is always a new object of one fixed class, so it cannot adapt such objects.

A common mistake. Forgetting that the adapter shows every method of the adaptee. Clients start to call these methods directly, and the target no longer hides the adaptee.