分享
 
 
 

设计模式、用Delphi描述-->Visitor模式

王朝delphi·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

Visitor 模式

起源

Delphi中的Visitor模式在基本Visitor模式进行了扩展。更多Visitor模式的资料请参 [Gam+, pages 331..344].

目的

表示一个作用于某个对象结构的中和元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

[Gam+, page 331].

动机

考虑一个面向对象的建模工具,比如说‘Rational Rose、ModelMaker’,它将一个模型表示为类和类的成员。

在建模工具上提供了许多操作成员功能,比如:列表类的所有成员、生成类的代码框架、反向工程等。

这些操作大多对不同的成员进行不同的操作。它将成员分成字段(fields)、方法(methods)、

属性(properties)。因些我们必须建立专门处理字段的类,专门处理methods的类等等。成员类的集合当然依赖被编译的语言。但对于一给定语言变化不大。

如图显示了部分成员类的框架。问题产生了,如果我将所有这些操作分散到不同的成员类,

将会导致整个系统难于理解,修改,维护。将类代码生成与类成员检查放在一起,将产生混乱。些外加入新的操作时要重新编译的有的类(至少也重新编译所有的相关的系)。有个办法:你可能独立的增加一个新的操作,并这个成员类独立如作用于其上的操作。

要实现上述两个目标,我们可以将每个类中相关操作包装在一上独立的对象(称为visitor)

并在遍历类成员列表时将此对象传递给当前成员。当一个成员‘接受’ 访问,该成员向访问者发送包含自身信息的请求。该成员请自本身作为一个参数。访问者执行这些操作。

例如:一个不使用访问者的代码生成器可能会通成员类的抽象的方法:TMember.WriteInterfaceCode(Output: TStream)生成代码。每一个成员都会调用WriteInterfaceCode生成适当的输出代码。如果通过访问者来生成代码,则会创建一个TinterfaceCodeVisitor对象,并在成员列表上调用参数为访问对象的AcceptVisitor方法。每一个在员在实现AcceptVisitor将会回调visitor:一个字段将调用访问者的VisitField方法,而一个方法则调用VisitMethod方法。这样,以前类Tfield的WriteInterfaceCode操作现在成为TinterfaceCodeVisitor的VisitField操作。

为使访问者不仅仅只做代码生成,我们需要所有的成员列表的访问者有一个抽象的父类TmemberVisitor。TmemberVisitor必须为每一个成员定义一种方法。一个需要将成员输出为HTML格式的应用将定义TmemberVisitor新的子类,并不再需要在成员类中增加与特定应用相关的代码。Visitor模式将每个操作封装在一个相关的Visitor中

使用Visitor模式,必须定义两个层次的类:一个应于接受操作的元素(Tmember层次)另一个定义于对元素的操作(TmemberVisitor 层次)。增加一个新的操作时只需给访问者层次增加一个新的子类。我可能简单的定义新的TmemberVisitor子类以增加新的功能。

应用

下面的代码演示上面描述的类Tmember的Visitor模式的应用

type

TMember = class (TObject)

public

procedure AcceptMemberVisitor(Visitor: TMemberVisitor); virtual;

end;

TField = class (TMember)

public

procedure AcceptMemberVisitor(Visitor: TMemberVisitor); override;

end;

TMethod = class (TMember)

public

procedure AcceptMemberVisitor(Visitor: TMemberVisitor); override;

end;

TProperty = class (TMember)

public

procedure AcceptMemberVisitor(Visitor: TMemberVisitor); override;

end;

TMemberVisitor = class (TObject)

public

procedure VisitField(Instance: TField); virtual;

procedure VisitMember(Instance: TMember); virtual;

procedure VisitMethod(Instance: TMethod); virtual;

procedure VisitProperty(Instance: TProperty); virtual;

end;

implementation

{ TMember }

begin

Visitor.VisitMember(Self);

end;

{ TField }

procedure TField.AcceptMemberVisitor(Visitor: TMemberVisitor);

begin

end;

{ TMethod }

procedure TMethod.AcceptMemberVisitor(Visitor: TMemberVisitor);

begin

Visitor.VisitMethod(Self);

end;

{ TProperty }

procedure TProperty.AcceptMemberVisitor(Visitor: TMemberVisitor);

begin

Visitor.VisitProperty(Self);

end;

{ TMemberVisitor }

procedure TMemberVisitor.VisitField(Instance: TField);

begin

end;

procedure TMemberVisitor.VisitMember(Instance: TMember);

begin

end;

procedure TMemberVisitor.VisitMethod(Instance: TMethod);

begin

end;

procedure TMemberVisitor.VisitProperty(Instance: TProperty);

begin

end;

说明:

· TMember, TField, TMethod 和 Tproperty都实现了AcceptMemberVisitor方法. 这些方法都嵌入模式中

· TMemberVisitor 类实现了VisitMember, VisitField等方法。TmemberVisitor是一个抽象的类,它所有的方法由具体的子类实现。

下面是一个简单的代码生成器的实现。

代码介绍:

· TCodeGenerationVisitor 是一个用于实现成员的代码生成器的访问者。

· 访问者定义了一个上下文相关的属性:Output: TTextStream,

· 它必须在VisitXXX调用前被定,如:DrawingVisitor典型的需要一个包括canvas的上下文,来支持画图操作。上下文在遍历整个member对列前赋予了代码生成器。

· 代码生成器将整结的生成的类的所有代码

要真正的了解Visitor模式,你可执行这个例子 ,并进一步的学习双分派机制: accept/visit.

unit CodeGenerators;

interface

uses Classes, TextStreams;

type

TCodeGenerator = class (TObject)

public

procedure Generate(Members: TList; Output: TTextStream);

end;

implementation

uses Members;

type

TCodeGenerationVisitor = class (TMemberVisitor)

private

FOutput: TTextStream;

public

procedure VisitField(Instance: TField); override;

procedure VisitMethod(Instance: TMethod); override;

procedure VisitProperty(Instance: TProperty); override;

property Output: TTextStream read FOutput write FOutput;

end;

{ TCodeGenerationVisitor }

procedure TCodeGenerationVisitor.VisitField(Instance: TField);

begin

Output.WriteLnFmt(' %s: %s;', [Instance.Name, Instance.DataName]);

end;

procedure TCodeGenerationVisitor.VisitMethod(Instance: TMethod);

var

MKStr, DTStr: string;

begin

case Instance.MethodKind of

mkConstructor: MKStr := 'constructor';

mkDestructor: MKStr := 'destructor';

mkProcedure: MKStr := 'procedure';

mkFuntion: MKStr := 'function';

end;

if Instance.MethodKind = mkFunction then

DTStr := ': ' + Instance.DataName

else

DTStr := '';

{代码不完整,现足以演示Tmethod代码生成 }

Output.WriteLnFmt(' %s %s%s%s;'

[MKStr, Instance.Name, Instance.Parameters, DTStr]);

end;

procedure TCodeGenerationVisitor.VisitProperty(Instance: TProperty);

begin

Output.WriteLnFmt(' property %s: %s read %s write %s;',

[Instance.Name, Instance.DataName,

Instance.ReadSpecifier, Instance.WriteSpecifier]);

end;

{ TCodeGenerator }

procedure TCodeGenerator.Generate(Members: TList; Output: TTextStream);

var

I: Integer;

begin

{写入类定义 }

Output.WriteLine('TSample = class (TObject)');

{好! 加入代码生成器的访问者}

Visitor := TCodeGenerationVisitor.Create;

Try

{记住为访问都提供上下文,以便更好的访问VisitXXX方法。}

for I := 0 to Members.Count - 1 do

{ 代码的具体段,好事情发生了}

TMember(Members[I]).AcceptMemberVisitor(Visitor);

finally

Visitor.Free;

end;

{类成员的代码生成完毕}

Output.WriteLine('end;');

end;

Delphi实例

正在组织

//很多摘自《设计模式》,

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有