1. Computing & Technology

Discuss in my forum

Indirection - Delphi OOP Part 8 - Chapter 18

By , About.com Guide

Materials written by John Barrow. Modifications by Zarko Gajic

Back to Chapter 17

Introducing (in this Chapter):

  • Chaining and delegation in RAD classes.
  • Patterns for the Law of Demeter and for Delegation.

Example 8.3 Delegation

As we mentioned, the data fields of the intermediate class, TMuseumCount in example 8.2, are public. Isn’t it almost a golden rule of object orientation that data fields are private, and that if we want to access these data fields from outside the unit, we must use access methods of some form or other?

This is an important rule, and we’ll incorporate it in this example. We’ll declare the TCounter objects in TMuseumCount as private data fields. TMuseumCount will have public access methods and properties which will interact with the TCounter objects. In doing this, we will move from chaining to delegation (or forwarding). Delegation overcomes the encapsulation leakage that is inevitably part of chaining.

The intermediate object now encapsulates the subsidiary objects instead of exposing them, with similar benefits to those in other forms of encapsulation. The cost is that we must now write access methods, which in this situation are also referred to as delegation methods or forwarding methods since they delegate or forward operations to other objects.

Ex 8.3 step 1 Using delegation

The revised version of MuseumCountU is:
 unit MuseumCountU;
 
 // using delegation
 
 interface
 
 uses CounterU;
 
 type
    TMuseumCount = class(TObject)
    private
      VEntered, VInside, VLeft: TCounter;
      // property mapping methods (use delegation)
      function GetEntered: integer;
      function GetInside: integer;
      function GetLeft: integer;
    public
      // read-only, method mapped properties using delegation
      property Entered: integer read GetEntered;
      property Inside: integer read GetInside;
      property Left: integer read GetLeft;
      constructor Create;
      procedure Arrivals (aNumber: integer) ;
      procedure ClearAll;
      procedure Departures (aNumber: integer) ;
    end;
 
 implementation
 
 { TMuseumCount }
 
 procedure TMuseumCount.Arrivals(aNumber: integer) ;
 begin
    VEntered.Add (aNumber) ;
    VInside.Add (aNumber) ;
 end;
 
 procedure TMuseumCount.Departures(aNumber: integer) ;
 begin
    VInside.Subtract (aNumber) ;
    VLeft.Add (aNumber) ;
 end;
 
 function TMuseumCount.GetEntered: integer;
 begin
    Result := VEntered.Total;
 end;
 
 function TMuseumCount.GetInside: integer;
 begin
    Result := VInside.Total;
 end;
 
 function TMuseumCount.GetLeft: integer;
 begin
    Result := VLeft.Total;
 end;
 
 procedure TMuseumCount.ClearAll;
 begin
    VEntered.Clear;
    VInside.Clear;
    VLeft.Clear;
 end;
 
 constructor TMuseumCount.Create;
 begin
    // propagate construction
    inherited Create;
    VEntered := TCounter.Create;
    VInside := TCounter.Create;
    VLeft := TCounter.Create;
 end;
 
 end. 
We have made the data fields private (line 8) with the result that we have to create six access methods. Three of these are mapped to read-only properties (VEntered, VInside and VLeft). The other three are mutator methods, though not Set methods (Arrivals, Departures and ClearAll).

These access methods all interact with the TCounter objects: TMuseumCount delegates all the data storage and manipulation to its subordinate objects, freeing the user interface from any concern over the details of the application logic.

From a different perspective, we can also say that the TMuseumClass is a composed class with three constituent TCounter objects: TMuseumCount is composed of (HasA) VEntered, VInside and VLeft objects.

Ex 8.3 step 2 Using the delegated methods

To use the new version of TMuseumCount we change the two OnClick event handlers in the user interface class as follows:
 procedure TfrmAttendance.btnEnterClick(Sender: TObject) ;
 begin
    MuseumCount.Arrivals (sedEnter.Value) ;
    lblIn.Caption := IntToStr(MuseumCount.Entered) ;
    lblVisitors.Caption := IntToStr(MuseumCount.Inside) ;
    sedEnter.Value := 0;
 end;
 
 procedure TfrmAttendance.btnLeaveClick(Sender: TObject) ;
 begin
    with MuseumCount do
    begin
      Departures (sedLeave.Value) ;
      lblOut.Caption := IntToStr(Left) ; // ** dangerous??
      lblVisitors.Caption := IntToStr(Inside) ;
    end;
    sedLeave.Value := 0;
 end; 

©2012 About.com. All rights reserved.

A part of The New York Times Company.