设计模式---Delphi 篇

本文以“观察者设计模式介绍 “对象--关系映射 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:

UML Visitors

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)
private
public
  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 file
gTIOPFManager.VisitorManager.Execute('read', FPeople);
// To save to a text file
gTIOPFManager.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》 即将补充完善,敬请关注!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第1章 ADO/MTS/COM十和分布式多层架构 1-1 认识ADO 1-2 使用原生ADO对象 1-3 ADO和分布式多层架构 1-4 Delphi的数据存取技术 1-5 原生ADO对象和ADOExpress组件 1-6 结论 第2章 撰写使用ADO技术的应用系统(一) 2-1 ADOExpress组件 2-2 数据库应用程序 2-3 Master/Detall应用程序 2-4 事务管理 2-5 BatchUpdate模式 2-6 搜寻数据 2-7 过滤数据 2-8 排序数据 2-9 结论 第3章 撰写使用ADO技术的应用系统(二) 3-l 处理多个数据表Join的数据 3-2 使用ADO处理BLOB信息 3-3 调用存储过程 3-4 使用ADO的异步执行能力 3-5 处理错误 3-6 使用ADO存取Excel 3-7 使用ADOx 3-8 RDS 3-9 使用ADO开发分布式多层应用系统 3-10 ADO和WebBroker应用程序 3-11 结论 第4章 深入了解ADO 4-l AD0的Cursor Engine 4-2 ADO修改数据的流程 4-3 ADOExpress和AD0 4-4 ADO和BDE/IDA贝 4-5 ADO的执行效率 4-6 优化ADO的执行效率 4-7 结论 第5章 MTS/COM+和分布式多层应用系统 5-1 什么是MTS 5-2 COM+COM的基本概念 5-3 MTS的系统架构 5-4 COM+的系统架构 5-5 状态对象和无状态对象 5-6 结论 第6章 MTS/COM+的核心技术事务管理 6-1 数据库事务管理 6-2 MTS/COM+事务对象 6-3 资源管理 6-4 MTS/COM+的事务生命周期 6-5 以程序代码自行控制事务管理 6-6 结论 第7章 MTS/COM+的安全机制 7-1 安全机制 7-2 MTS/COM+的角色 7-3 实现宣告式安全机制 7-4 资源鉴定控制 7-5 安全机制检查的时机 7-6 实际的范例 7-7 结论 第8章 设计MTS/COM+对象和MTS/COM+应用系统 8-1 开发MTS/COM+组件 8-2 开发存取数据的MTS/CoM+组件 8-3 较为复杂和实际的MTS/COM+应用系统 8-4 MT3/COM+的共享信息机制 8-5 管理和分发MTS/COM+应用系统 8-6 如何调试MTS/COM+应用系统 8-7 结论 第9章 以DeIphi技术开发MTS/COM+应用系统 9-l 一个典型的场景 9-2 使用TDCoMConnection建立MTS/COM+对象 9-3 维护事务管理的正确性 9-4 MTS/COM+应用系统架构的实现 9-5 第二种思考方式 9-6 结论 第10章 撰写高效率的MTS/COM+组件和MTS/COM+应用系统 10-1 你应该牢记的事情 10-2 快速建立和调用远程MTS/COM+对象 10-3 MTS/COM+对象和数据的传送 10-4 状态信息 10-5 结论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值