Chinaunix首页 | 论坛 | 博客
  • 博客访问: 29021014
  • 博文数量: 101
  • 博客积分: 4011
  • 博客等级: 上校
  • 技术积分: 1150
  • 用 户 组: 普通用户
  • 注册时间: 2007-10-18 10:37
个人简介

落魄青年,挨踢民工,已经转行

文章分类

全部博文(101)

文章存档

2008年(47)

2007年(54)

分类:

2007-10-19 15:10:25

建立一个抽象的基类业务对象

一个基类业务对象可以让你扩展Delphi的可视化开发能力,你可以将你的可视化控件绑定到你的业务对象上,而不是通常直接绑定到数据集。(在本文的例子中,实际上是绑定在业务对象中的数据集上)。基类业务对象让你集中一些在派生类共同的行为并且以一致的方式来处理(应该是多态的)。

 

Unit base;
interface

uses
   Windows, Messages, SysUtils, Classes, Graphics,
   Controls, Forms, Dialogs, Db, DBTables;
{
This is the base class for all business objects. This contains behavior that you want to be common in the system as a whole.In this example we will be just putting some simple locking mechanisms. Other things that we may want to put in this object could be validations, common behavior for locking etc. We will place our common table object on this so we have a point of reference for the other objects to work off.
}
type
   TBizObj = class(TDataModule)
        q_data: TQuery;
        procedure q_dataAfterPost(DataSet: TDataSet);
        procedure q_dataAfterCancel(DataSet: TDataSet);
        procedure q_dataBeforeEdit(DataSet: TDataSet);
        procedure q_dataBeforeDelete(DataSet: TDataSet);
        procedure q_dataBeforePost(DataSet: TDataSet);
        private
        public
   end;
var
   BizObj: TBizObj;

Implementation

{$R*.DFM}
procedure TBizObj.q_dataAfterPost(DataSet: TDataSet);
begin
   // release our optimistic lock
end;
procedure TBizObj.q_dataAfterCancel(DataSet: TDataSet);
begin
   // release out optimistic locks
end;
procedure TBizObj.q_dataBeforeEdit(DataSet: TDataSet);
begin
   // put code here to place an optimistic lock on this
   // row in the table
end;
procedure TBizObj.q_dataBeforeDelete(DataSet: TDataSet);
begin
   // check the optimistic lock for contentions
end;
procedure TBizObj.q_dataBeforePost(DataSet: TDataSet);
begin
   // check the optimistic lock for contentions,
end;
end.

定义一个公用接口

一旦你派生类化了一个Tdatamodule,你必须在这个派生类中定义公共接口。这实际上是一个很简单的练习,因为我们在定义这个类的时候已经做了分析。公共接口包括了可以被别的对象操作的方法和属性。在这个数据库应用程序的例子中,数据成员可能主要是Tfield的后代类,通常是通过定义Dataset类加入到业务对象中。

type
        TAccount = class(T_BizObj)
          private
                { Private declarations }
          public
           procedure withdraw(amount : float);
           procedure deposit(amount : float);
           procedure transferTo(amount : float,
                toAccount : TAccount);
           function canIWithDraw(amount: float) : boolean;
      end;

实现数据访问

现在,你要为你的TAccount类设计公共数据访问方法,我们需要实现基本数据访问。还记得这个TAccount类是抽象的吗?它不能被实例化,只有它的后代类才可能。我们打算用第三种数据库映射方式来存储我们的Account,因此我们的表结构看起来像下面这个样子:

Account
  Nbr: int
  Amount : double
  AccountHolderName : Char(40)
  DateOpened : DateTime
  DateClosed : DateTime
  Descr : Char(80)

CheckingAccount
  Nbr
  OverdraftAccountNbr

SavingsAccount
  Nbr
  MinBalance

实现数据访问就像以往写的代码一样,唯一不同的就是我们现在在“业务对象”中写访问方法。你可能想要一个方法去得到你感兴趣的账户。但是,在一个Account对象中出现多个账户是不合法的(真实世界不会这样)。正确的类交互方式应该是请求Tbank对象按条件查询账户,返回一些Account对象。下面是我们的账户对象,它包含了一些数据访问方法。

 

我们打算利用SQL 数据库的查询,我们需要一个参数化的查询来从服务器得到我们需要的账户资料。

 

我们同样需要在账户对象上一个方法来打开账户,我们的Account对象的公共接口方法看起来如下面所示:
type
   TAccountBO = class(TBizObj)
   private
     { Private declarations }
   public
      procedure getAccount(AcctNbr : integer);
      procedure withdraw(amount : double);
      procedure deposit(amount : double);
      procedure transferTo(amount : double; account : TAccountBO);
      function canIWithDraw(amount : double): boolean;
   end;

在这个getAccount( )方法的实现中,我们需要在Account对象中打开适当的账户数据

procedure TAccountBO.getAccount(AcctNbr : integer);
begin
   if (q_data.Active)
      begin
         // check to see if we can close this account
      end;

   q_data.close;
   q_data.parambyname('Nbr').value = acctNbr;
   q_data.open;
   // check to see if there is a record, if not raise an error
end;

建立我们的派生类TCheckingAccount, TsavingsAccount

对于每个特殊的账户类型,我们需要它们创建合适的具体的派生类,它们实现自己特殊的行为,规则和数据访问.为了避免陷入太多的细节,我仅仅重点讲一下派生类部分.

 

建立自己的数据访问,依赖你自己的数据访问策略,你可能要加入相关的数据访问控件或者改变Taccount的默认方式.在你的业务对象中还要放入数据验证方法.因为你建立的是一个新的类型,因此完全可以放置特殊的验证(可能用事件驱动方式,当某件事情发生是,在事件相应中执行),也可能有自己外在的控制行为,比如一些基类不能做在派生类中可以做的事情.

 

为这个业务对象建立用户接口,有可能这个派生类跟它的基类对用户接口有不同的考虑.

 

建立 TBank 类

Tbank是管理所有账户的类别.由于时间和空间关系,我不打算真正实现一个完整的Tbank类的构造(如果这样的话,我们有很多的细节问题要处理).在这个简单的例子中,Tbank对象可以提供TAccount对象的列表,并且可以打开和维护账户.由于空间关系,Tbank的完整代码我没有列出来.

 

实现私有的和保护接口

当我们定义类的属性和公共方法之后,我们需要实现它的功能和业务规则. 不要把数据成员变量放在类的公共接口中是一个好的习惯.Delphi的”属性”可以提供透明的数据存储,你仍然可以设置和访问这个数据成员.另一个好的习惯是将属性的读写方法设置为virtual(虚方法),如果派生类需要,可以覆盖它.

阅读(1771) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~