This factory methods pattern is based on that described in [Gam+, pages 107..116]. The Delphi implementation for the pattern is from Shaun Parry.
'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].
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.