Factory Method pattern

Origin

This factory methods pattern is based on that described in [Gam+, pages 107..116]. The Delphi implementation for the pattern is from Shaun Parry.

 

Intent

'Define an interface for creating an object, but let the subclasses decide which class to instance. Factory method lets a class defer instantiation to subclasses' [Gam+,p107].

 

Motivation

The motivation is based on [Gam+, page 107]. Basically, the factory method is a way of combining some of the principals of Builder and the Abstract Factory but without the additional factory/builder class. All the methods are contained within the maker class and any variations you require are done by overriding the methods of the maker class.

Implementation

The following is an example of making a panel with three edit boxes within it, as with the Abstract Factory pattern. Again we are going to use a class called PanelMaker, but this time we're going to add the making methods :
 

type
 TPanelMaker = class (TObject)
 public
   function CreatePanel(aOwner : TWinControl): TPanel; virtual;
   function MakeButton(aOwner : TWinControl;
                       Caption : string;
                       Top : Integer;
                       Left : Integer): TButton; virtual;
   function MakeEdit(aOwner : TWinControl;
                     Top : Integer;
                     Left : Integer): TEdit; virtual;
   function MakePanel(aOwner : TWinControl): TPanel; virtual;
 end;

implementation

function TPanelMaker.CreatePanel(aOwner : TWinControl): TPanel;
var
  TempPanel: TPanel;
begin
  TempPanel := MakePanel( aOwner );
  TempPanel.Height := 100;
  TempPanel.Width := 150;
  MakeEdit( TempPanel, 10, 10 );
  MakeEdit( TempPanel, 40, 10 );
  MakeEdit( TempPanel, 70, 10 );

  CreatePanel := TempPanel;
end;

function TPanelMaker.MakeButton(aOwner : TWinControl;
                                Caption : string;
                                Top : Integer;
                                Left : Integer): TButton;
var
  TempButton: TButton;
begin
  TempButton := TButton.Create( aOwner );
  TempButton.Parent := aOwner;
  TempButton.Caption := Caption;
  TempButton.Top := Top;
  TempButton.Left := Left;

  result := TempButton;
end;

function TPanelMaker.MakeEdit(aOwner : TWinControl;
                              Top : Integer;
                              Left : Integer): TEdit;
var
  TempEdit: TEdit;
begin
  TempEdit := TEdit.Create( aOwner );
  TempEdit.Parent := aOwner;
  TempEdit.Top := Top;
  TempEdit.Left := Left;
  TempEdit.Width := 121;
  TempEdit.Height := 21;
  result := TempEdit;
end;

function TPanelMaker.MakePanel(aOwner : TWinControl): TPanel;
var
  TempPanel: TPanel;
begin
  TempPanel := TPanel.Create( aOwner );
  TempPanel.Parent := aOwner;
  result := TempPanel;
end;

Notice that each stage of the process, making the panel, making the edit boxes, assembling the panel, etc. are separate functions. This makes it easier to change the different parts of the process of creating the panel. For example, we can now create a derivative of TPanelMaker called TButtonPanelMaker:

 

type
  TButtonPanelMaker = class (TPanelMaker)
  public
    function CreatePanel(aOwner : TWinControl): TPanel; override;
  end;

implementation

function TButtonPanelMaker.CreatePanel(aOwner : TWinControl): TPanel;
var
  TempPanel: TPanel;
begin
  TempPanel := MakePanel( aOwner );
  TempPanel.Height := 100;
  TempPanel.Width := 200;

  MakeEdit( TempPanel, 10, 10 );
  MakeEdit( TempPanel, 40, 10 );
  MakeEdit( TempPanel, 70, 10 );
  MakeButton( TempPanel, 'OK', 10, 130 );
  MakeButton( TempPanel, 'Cancel', 40, 130 );

  CreatePanel := TempPanel;
end;

This derivative changes CreatePanel to give the new panel a couple of buttons.