1. Home
  2. Computing & Technology
  3. Delphi Programming

The Adapter Pattern - Delphi OOP Part 10 - Chapter 22

By Zarko Gajic, About.com

Materials written by John Barrow. Modifications by Zarko Gajic

Back to Chapter 21

Delegation: Association and Composition

The previous two parts (parts 8 and 9) have introduced us to the concepts of association, composition and delegation. Briefly stated, we write a new class that refers to or incorporates an instance of another class, in the sense of carrying a link to it, and then calls its methods to use some or all of that class’s functionality without having to re-implement it.

By allowing one to incorporate the facilities of an existing class into a new class, delegation has some similarity to inheritance. However, unlike inheritance, each required facility must be exposed explicitly. While this requires more work on the part of the rogrammer, it also allows facilities of the existing class to be kept hidden, something not possible through inheritance.

If a single class delegates operations to more than one existing class, an effect similar to multiple inheritance is possible while avoiding some of the complications.

Delegation is an important OO principle and is used in a variety of patterns such as the Adapter, the Facade and the Strategy patterns. In this part we look at the Adapter and Facade patterns.

Example 10.1 The Adapter Pattern

A composed object is the owner of constituent objects that it can use while hiding them from others. This opens up the possibility of adapting legacy software or existing classes for reuse.

When looking for reuse of existing software in a new application we may find a class or a non-OO program that performs the operations we need but that does not meet some other requirement or that may be subject to future change. Adapting accommodates these factors by encapsulating this existing software as an object and limiting its coupling with the rest of the program.

This example presents the Adapter Pattern as a way of reusing legacy software within an OO programming approach. The next example shows how an object in one hierarchy may be adapted to another inheritance hierarchy when this is required for polymorphism.

Ex 10.1 step 1 A legacy class

Assume that we are programming to a standard that requires separate access methods for modifying and for reading object data, and that these methods must work with a consistent data type. We have an existing TCounter class that does not meet these standards.

First, its access methods (the methods AddAndRead and ClearAndRead below) both modify the value of the field data and return a value, which is not good programming practice.

Second, its access methods accept an integer and return a string. According to the standard these should be of the same type. We want to reuse this class but we don’t want to ignore our standards, so we can create an adapter with the required interface. The existing class is:

unit CounterU;

// Legacy class

interface

type
   TCounter = class (TObject)
   protected
     Total : Integer;
   public
     function AddAndRead (Number : Integer): string;
     function ClearAndRead: string;
   end;

implementation

uses
   SysUtils;

function TCounter.AddAndRead (Number : Integer): string;
begin
   Total := Total + Number;
   Result := IntToStr (Total) ;
end;

function TCounter.ClearAndRead: string;
begin
   Total := 0;
   Result := IntToStr (Total) ;
end;

end.

Ex 10.1 step 2 The Adapter class

We create a composed class that has the method signatures required by the standards (the methods Add, Clear and GetValue) and that adapts these to calls to the legacy class:
unit NewCounterU;

// 'Simple' adapter, no local processing or data

interface

uses
   CounterU; // contains adapted class

type
   TNewCounter = class(TObject)
   private
     FOldCounter: TCounter; // the adaptee, kept private
   public
     // composition: must propagate create and destroy
     constructor Create;
     destructor Destroy; override;
     // adapter methods providing the required interface
     procedure Add (ANumber: integer) ;
     procedure Clear;
     function GetValue: integer;
   end;

implementation

uses SysUtils;

{ TNewCounter }

procedure TNewCounter.Add(ANumber: integer) ;
begin
   FOldCounter.AddAndRead (ANumber) ;
end;

procedure TNewCounter.Clear;
begin
   FOldCounter.ClearAndRead;
end;

constructor TNewCounter.Create;
begin
   inherited;
   FOldCounter := TCounter.Create;
end;

destructor TNewCounter.Destroy;
begin
   FOldCounter.Free;
   inherited;
end;

function TNewCounter.GetValue: integer;
begin
   Result := StrToInt (FOldCounter.AddAndRead(0)) ;
end;

end.
Zarko Gajic
Guide since 1998

Zarko Gajic
Delphi Programming Guide

Explore Delphi Programming
About.com Special Features

Stay connected and entertained with reviews on tips on the latest HDTVs, cellphones and more. More >

Easy ways to connect two computers for networking purposes. More >

  1. Home
  2. Computing & Technology
  3. Delphi Programming
  4. Coding Delphi Applications
  5. OOP in Delphi
  6. Free Online OOP Course
  7. The Adapter Pattern - Delphi OOP Part 10 - Chapter 22

©2009 About.com, a part of The New York Times Company.

All rights reserved.