抽象工厂(abstract factory)模式
出处
本模式源于设计模式一书,但模式的DELPHI实现是由Shaun Parry 完成的。
意图
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
动机
[详细的动机说明请参见设计模式一书],考虑一个复合类,它在不同的应用程序中创
建时都将包含有相同的成员但又各有不同。就像你有一份文档,用不同的打印机打印出
来看上去会各有一点不同,但无论用什么打印机打印,最后打出来的文档内容应该都是
相同的。抽象工厂真正的内涵是你可以传递具有相同接口的一个类(也就是那个工厂)
给构造器,这个接口是被构造器所用的,但接口的具体实现方法,却由不同的工厂来确
定。
在上面的类流程图中,你可以看到Client类的函数CreateProduct是如何调用抽象工厂
(AbstractFactory)类的CreateProduct函数来创建一个AbstractProduct类的对象。因
为在Client类和ConcreteProduct类之间并没有任何直接的牵连,所以ConcreteProduct
可以是任何一个AbstractProduct的子类。
实现
下面是一个用来创建上面带有三个编辑框(edit boxe)的面板(panel)的例子,在这个例
子中,我们准备用专门创建的一个叫PanelMaker的类的CreatePanel方法来创建我们的
面板。
Type
TPanelMaker = class (TObject)
public
function CreatePanel( aOwner : TWinControl;
Factory : TAbstractFactory ): TPanel;
end;
implementation
function TPanelMaker.CreatePanel(aOwner : TWinControl;
Factory : TAbstractFactory): TPanel;
var
TempPanel : TPanel;
TempEdit1 : TEdit;
TempEdit2 : TEdit;
TempEdit3 : TEdit;
begin
TempPanel := Factory.MakePanel( aOwner );
TempEdit1 := Factory.MakeEdit( TempPanel, 'Test1', 10, 10 );
TempEdit2 := Factory.MakeEdit( TempPanel, 'Test2', TempEdit1.Top + TempEdit1.Height + 10,
TempEdit1.Left );
TempEdit3 := Factory.MakeEdit( TempPanel, 'Test3', TempEdit2.Top + TempEdit2.Height + 10,
TempEdit2.Left );
CreatePanel := TempPanel;
end;
请注意,我们并没有直接用TPanel.Create来创建我们的面板,而是用了一个抽象工厂的
方法MakePanel来代替它,这样,如果我们要改动的时候,将变得更加容易。
抽象工厂的具体定义如下:
type
TAbstractFactory = class (TObject)
protected
FPanel : TPanel;
public
function MakeEdit( aOwner : TWinControl;vText : string;vTop : Integer;vLeft : Integer ): TEdit;
virtual;
function MakePanel( aOwner : TWinControl ) : TPanel;
virtual;
end;
implementation
function TAbstractFactory.MakeEdit( aOwner : TWinControl;vText : string;vTop : Integer;vLeft : Integer ): TEdit;
var
TempEdit : TEdit;
begin
TempEdit := TEdit.Create( aOwner );
TempEdit.Parent := aOwner;
TempEdit.Text := vText;
TempEdit.Top := vTop;
TempEdit.Left := vLeft;
MakeEdit := TempEdit;
end;
function TAbstractFactory.MakePanel( aOwner : TWinControl ) : TPanel;
var
TempPanel : TPanel;
begin
TempPanel := TPanel.Create( aOwner );
TempPanel.Parent := aOwner;
MakePanel := TempPanel;
end;
这个定义是用来创建标准编辑框和标准面板的,但是,如果我们想要创建一个特殊类型
的编辑框,比如说,我们希望那个编辑框只允许大写字母。
Type
TUppercaseEdit = class (TEdit)
protected
FOnChange : TNotifyEvent;
procedure Change;
override;
function GetUppercase : string;
procedure SetUppercase( Value : string );
public
property Text : string read GetUppercase write SetUppercase;
end;
现在你可以创建一个用这个编辑框来代替标准编辑框的抽象工厂类的子类。
function TUppercaseFactory.MakeEdit( aOwner : TWinControl;vText : string;vTop : Integer;vLeft : Integer ): TEdit;
var
TempEdit : TUppercaseEdit;
begin
TempEdit := TUppercaseEdit.Create( aOwner );
TempEdit.Parent := aOwner;
TempEdit.Text := vText;
TempEdit.Top := vTop;
TempEdit.Left := vLeft;
MakeEdit := TempEdit;
end;
就像这样,你并不需要对PanelMaker.CreatePanel方法有任何改动。