设计模式---Delphi 篇
来源:互联网 发布:虚拟机ubuntu大小调整 编辑:程序博客网 时间:2024/05/15 01:11
本文以“观察者”设计模式介绍 “对象--关系映射 ORM ”
下面以Delphi tiOPF 框架实现原理介绍:
Abstract the Visitor logic
Before we go any further, we must abstract the Visitor functionality away from the business objects so we never have to touch it again. We will do this in three stages. We will create abstract TVisitor and TVisited classes, then we will create an abstract business object, and business object list that will descend from TVisited. We will then re-factor our TPerson and TPeople classes to descend from the newly created abstract classes.
The class diagram of what we are aiming to build looks like this:
The TVisitor has two methods, AcceptVisitor( ) and Execute( ). Both taking a single parameter of type TVisited. The TVisited has a single method called Iterate( ) which takes a single parameter of type TVisitor. TVisited.Iterate( ) calls the Execute method on the Visitor that is passed as a parameter against itself, and if it contains other object, against each one of the too. The function TVisitor.AcceptVisitor is necessary because we are building a generic framework. It will be possible to pass a visitor that is designed for handling TPeople a concrete instance of, say a TDog and we must have a mechanism for preventing this from causing an access violation. The TVisited descends from TPersistent because down the track, we will be implementing some functionality that requires RTTI. The interfaces of TVisitor and TVisited are shown below:
TVisitor = class(TObject)protected function AcceptVisitor(pVisited : TVisited): boolean; virtual; abstract;public procedure Execute(pVisited : TVisited ); virtual; abstract;end; // Both AcceptVisitor and Execute must be implemented in the concreate
TVisited = class(TPersistent)public procedure Iterate(pVisitor: TVisitor); virtual;end;
Both TVisitor.AcceptVisitor and TVisitor.Execute must be implemented in the concrete class. The implementation of TVisited.Iterate, which contains a call to TVisitor.Execute, is shown below:
procedure TVisited.Iterate(pVisitor: TVisitor);begin pVisitor.Execute( self ) ;end;
Step #5. Create an abstract business object, and abstract list object
We require two more abstract classes in our framework: An abstract business object, and a list container for the abstract business object. We shall call these TtiObject and TtiObjectList and the interface of these classes is shown below:
TtiObject = class(TVisited)privatepublic constructor Create; virtual;end;
We will be adding significantly to TtiObject when we look in more detail at the business object framework, but for the time being, we just add a virtual constructor so we can uniformly override the constructor in descendent classes.
We want our list class, TtiObjectList to descend from TVisited so the generic visitor behavior can be implemented (actually, we want it to descend from TtiObject for reasons we will discuss later). Ideally, we would use interfaces to give our list class the iteration behavior, but much of this code base predates the popularity of interfaces, and I have not faced up to the task of re-factoring to take advantage the benefits they can offer.
To create a list class which descends from TVisited and TtiObject, we shall use object containment. The interface of TtiObjectList is shown below and the implementation is pretty much what you would expect.
TtiObjectList = class(TtiObject)private FList: TObjectList; function GetList: TList;public constructor Create; override; destructor Destroy; override; property List: TList read GetList; procedure Iterate( pVisitor: TVisitor); override; procedure Add(pData: TObject);end ;
The most important method in this class is the overridden procedure Iterate. In the abstract class TVisitor, iterate is implemented as the one line call pVisitor.Execute(self). In the TtiObjectList it is implemented like this:
procedure TtiObjectList.Iterate(pVisitor: TVisitor);var i : integer ;begin inherited Iterate(pVisitor); for i := 0 to FList.Count - 1 do (FList.Items[i] as TVisited).Iterate(pVisitor);end;
This is an important core concept. We now have two abstract business objects TtiObject and TtiObjectList. Both have an Iterate method that is passed an instance of a TVisitor as a parameter. In each case, the TVisitor’s Execute method is called with self as a parameter. This call is made via inherited at the top of the hierarchy. For the TtiObjectList class, each object in the owned list also has its Iterate method called with the visitor being passed as the parameter. This ensures that all objects in the hierarchy are touched by the Visitor.
Step #6. Create a Visitor manager
Now, back to the original problem we created for our selves in step #3. We don’t want to be spending all our time creating and destroying visitors. The solution is in the Visitor Manager.
The Visitor Manager performs two main tasks: It maintains a list of registered visitors (visitors are registered in the implementation section of the unit where they are declared.); and calls a group of visitors that are registered with a given command name against the data object it is passed.
To implement the Visitor manager, we will define three more classes: The TVisClassRef, TVisMapping and the TtiVisitorManager.
The TVisClassRef is a class reference type that will hold an instance TVisitor’s class. I find the help text description of class references a little confusing. The best way to understand them is with an example. Lets say we have our abstract Visitor class TVisitor, and a Visitor class reference type TVisClassRef. We also have a concrete Visitor called TSaveVisitor. The TVisClassRef type is declared like this:
TVisClassRef = class of TVisitor ;
This lets us write code like this:
procedure ExecuteVisitor(const pData: TVisited; const pVisClass: TVisClassRef);var lVisitor: TVisitor;begin lVisitor := pVisClass.Create; try pData.Iterate(lVisitor); finally lVisitor.Free; end;end;
We pass two parameters to this procedure; pData which is an instance of TVisited (like our TPeople), a TVisClassRef, which could be TShowNameVisitor or TShowEMailAdrsVisitor. This procedure takes care of the tedious business of creating the visitor, calling iterate, then freeing the visitor when done.
The second class we create for our visitor manager is called TVisMapping. It is a simple data structure to hold two pieces of information: a TVisClassRef and a string called Command. The interface of TVisMapping is shown below:
TVisMapping = class(TObject)private FCommand: string; FVisitorClass: TVisClassRef;public property VisitorClass: TVisClassRef read FVisitorClass write FVisitorClass; property Command: string read FCommand write FCommand;end;
The final class we create is the TtiVisitorManager. When we register a Visitor with the Visitor Manager, an instance of TVisMapping is created and added to the list inside the TtiVisitorManager. The command and VisitorClass properties are set which allows us to execute a group of visitors identified by a string. The interface of the TtiVisitorManager is shown below:
TtiVisitorManager = class(TObject)private FList: TObjectList;public constructor Create; destructor Destroy; override; procedure RegisterVisitor(const pCommand: string; pVisitorClass: TVisClassRef); procedure Execute(const pCommand: string; pData: TVisited);end;
The key methods here are RegisterVisitor and Execute. RegisterVisitor is called in the implementation section of the unit where the Visitor is defined and is typically called like this:
initialization gTIOPFManager.VisitorManager.RegisterVisitor('show', TShowNameVisitor); gTIOPFManager.VisitorManager.RegisterVisitor('show', TShowEMailAdrsVisitor);
The implementation of RegisterVisitor is shown below (this code is much the same as the code found in a Delphi implementation of the Factory Pattern)
procedure TtiVisitorManager.RegisterVisitor(const pCommand: string; const pVisitorClass: TVisClassRef);var lData: TVisMapping;begin lData := TVisMapping.Create; lData.Command := pCommand; lData.VisitorClass := pVisitorClass; FList.Add(lData);end;
The other important method in the TtiVisitorManager is Execute. Execute takes two parameters, the command name which identifies the family of visitors to be executed, and the data object which is at the top of the tree to be iterated over. The implementation of Execute is shown below:
procedure TtiVisitorManager.Execute(const pCommand: string; const pData: TVisited);var i: integer; lVisitor: TVisitor;begin for i := 0 to FList.Count - 1 do if SameText(pCommand, TVisMapping(FList.Items[i]).Command) then begin lVisitor := TVisMapping(FList.Items[i]).VisitorClass.Create; try pData.Iterate(lVisitor); finally lVisitor.Free; end; end;end;
To execute both the ShowName and ShowEMailAdrs visitors (the ones we registered above), one after the other we would make the following call to the Visitor manager.
gTIOPFManager.VisitorManager.Execute('show', FPeople);
Next, we will create some persistent Visitors that will let us make calls like
// To read from a text filegTIOPFManager.VisitorManager.Execute('read', FPeople);// To save to a text filegTIOPFManager.VisitorManager.Execute('save', FPeople);
but first we will use the tiListView and tiPerAwareControls to create a GUI to use while editing the list of TPeople.
参考更多:
1、http://tiopf.sourceforge.net/Doc/Concepts/2_TheVisitorFramework.shtml
2、微软.NET框架 关于“观察者”模式、委派/事件:
http://www.microsoft.com/china/MSDN/library/enterprisedevelopment/builddistapp/ExploringtheObServerDesignPattern.mspx?mfr=true
《未完待续07.04.07》 即将补充完善,敬请关注!!!
- 设计模式---Delphi 篇
- Delphi设计模式-Abstract Factory
- Delphi中的Wrapper设计模式
- Delphi五种设计模式
- delphi版大话设计模式
- 用 Delphi 学设计模式 之 简单工厂篇- -
- 用Delphi学设计模式之工厂方法篇
- 设计模式、用Delphi描述-->Observer模式
- Delphi 设计模式:《HeadFirst设计模式》Delphi7代码---状态模式
- HeadFirst设计模式——delphi版
- Delphi 设计模式:《HeadFirst设计模式》Delphi代码---工厂模式之抽象工厂
- 设计模式学习笔记5:Singleton模式及其Delphi实现
- 设计模式、用Delphi描述-->Observer模式
- 设计模式、用Delphi描述-->Factory Method模式
- 设计模式、用Delphi描述-->Abstract Factory模式
- 设计模式、用Delphi实现---->Template Method模式
- Delphi设计模式之单例模式(Singleton Pattern)
- 《大话设计模式》之 策略模式 Delphi实现
- 数的智慧与力量
- [转贴]精妙Sql 15句
- Delphi语句用法-我原来作项目用到的语句整理
- 一些常用的JS函数
- Delphi文件管理
- 设计模式---Delphi 篇
- 框架之间的应用
- 记录文件实例与调用
- 根据企业信息化应用需求来分析工作流平台(工作流引擎)的选型
- Subversion权限控制
- javascript学习笔记
- MyEclipse5.1中使用hibernate3.1(lp)
- javascript教程
- [英雄会专访系列]专访浪潮研发中心总经理周恒:独特的奖罚文化