Wrapper pattern
起源
Delphi中的Wrapper模式是在 ‘Adapter’ or ‘Wrapper’ 的基础上上改造的。更多的介绍请查阅[Gam+, pages 139..150]。
目的
‘将一个接口转换成客户期待的别外一个接口。Wrappers 模式使得原本由于接口不兼容而不能一起工作类可以一起工作,参阅 [Gam+ 139].
动机
在Delphi的Object Pascal语言中类对多态性的支持远比接口对多态的支持高。同样意味着两个类虽然可以同时支持一个接口,但它们必须有相同的组先类,从而客户对象可以对类执行动态变换。但有时我们想使一些原本无关的类在一起工作,此时wrapper模式让你将一类包装成另一个类的接口。它类同于多重继承,但在Delphi是一种引用关系。
开始讲述下面的例了,好:
假设您有一个继承自Tobject并想安装到控件板的类:Tsample,但此时必须让组件支持Tcomponent。高兴的是有一种好的办法不用改变Tsample的继承关系就可以将转换成支持
Tcomponent(比如此时你没有类的源码,只有它的BPL包),创建一个继承于Tcomponent的新类TsampleWrapper,并将引用聚合类Tsample。此后类TsampleWrapper将是Tcomponent后代,你可以将它加入控件板了。你现在将Tsample包装成TsampleWrapper的一个成员变量,并为它接供一个专用的访问接口。TsampleWrapper将被委托接受它包装的类的所有行为。这样客户就可能适当的调用Sample的方法及Sample的属性。
另外一种方法使用wrapper pattern关有符合‘Law of Demeter’。些规律的基础是让你不要引用太深的对象。Tsample的访问接口和TsampleWrapper的关系如下:
type
TSample = class (TObject)
private
FSomeValue: Integer;
public
function SomeAction(const Data: string): Boolean;
property SomeValue: Integer read FSomeValue write FSomeValue;
end;
TSampleWrapper = class (TComponent)
private
FSample: TSample;
public
property Sample: TSample read FSample;
end;
依照‘Demeter’s law’访问SampleWrapper.Sample是很好的。但SampleWrapper.Sample.SomeAction却不是好的实例。好的想法是在类TsampleWrapper中定义一个SomeAction方法,并通过SomeAction调度Sample.SomeAction方法。
你可能经常写过这样的代码:ListBox.Canvas.Brush.Color。 看起来有点违背 ‘Demeter’s law’
应用
上面描述的类演示了一个wrapper模式的应用。类TsampleWrapper聚合Tsample类,并接供了一个Sample的属性接口。现在我们创建一个更完整的wrapped模式的应用,为类TSampleWrapper创建一个叫SomeAction和一个叫SomeValue属性接口,
TSampleWrapper = class (TComponent)
private
FSample: TSample;
protected
function GetSomeValue: Integer;
procedure SetSomeValue(Value: Integer);
public
function SomeAction(const Data: string): Boolean;
» property Sample: TSample read FSample;
property SomeValue: Integer read GetSomeValue write SetSomeValue;
end;
可以看出来了,通过TsampleWrapper的SomeAction方法比引用SampleWrapper.Sample.SomeAction更直接。
类TsampleWrapper的实现代码如下:(一个可以编译的代码段)
function TSampleWrapper.GetSomeValue: Integer;
begin
Result := Sample.SomeValue;
end;
procedure TSampleWrapper.SetSomeValue(Value: Integer);
begin
Sample.SomeValue := Value;
end;
function TSampleWrapper.SomeAction(const Data: string): Boolean;
begin
Result := Sample.SomeAction(Data);
end;
说明一下类TsampleWrapper:
· 被包装的成员的特性,在包装类中都有着同样的类型,如名称、数据类型,可见性、及其它个别特性。
· 被包装成员的属性也被包装成属性,并且可能通过read、write方法访问。
· 被包装的成员也接供了属性访问接口,也可能通过read、write方法访问。
· 事件与被包装起来,通过read、write方法访问方法,胜于直接访问事件句柄。
· 方法也被包装起来了,并复接被包装类的方法的参数集、现样返回值也是被包装类的返回值。
Delphi实例
正在组织。