讲解三层代码讲解(DLL规则层如何接收服务器的数据,又如何交回给服务器)--第四课(*****) DATE :2004-06-01

主题:讲解三层代码讲解(DLL规则层如何接收服务器的数据,又如何交回给服务器)--第四课(*****)
主讲:A1
时间:2004-06-01 15:00

2004-06-01 14:57:31 烟灰缸
我们开始好了,其它的朋友就不等了。。。。。

2004-06-01 14:57:54 烟灰缸
我们上次的讨论到了哪里了?

2004-06-01 14:59:20 dana
swServer2.exe

2004-06-01 14:59:28 Jackey
今天只是讲到服务器(如何接收、中转的) 

2004-06-01 14:59:59 Jackey
  property BaseService: IBaseService read GetBaseService write SetBaseService;
    property Module: integer read GetModule write SetModule;
    property ModuleInfo: WideString read GetModuleInfo;
 

2004-06-01 15:00:15 烟灰缸
应该是这里吧。

2004-06-01 15:00:39 松鼠
能不能有个大概的回顾?

2004-06-01 15:01:11 烟灰缸
斜阳
今天基本上把客户端和服务器交互的过程简单理清了点了,明天是不是要将业务规则动态库了,看看是如何根据中转服务器中转过来的东西逐步调用子规则并合成数据的,是吧 

2004-06-01 15:01:19 烟灰缸
上次是到这里吧?

2004-06-01 15:01:40 烟灰缸
(客户端)请求数据流(如何请求的)->(如何到服务器的)->服务器(如何接收、中转的)->(如何返回的)->数据数据流(客户端)
 

2004-06-01 15:01:58 斜阳
差不多

2004-06-01 15:02:04 烟灰缸
上次只是讲到服务器(如何接收、中转的) 还有客户端如何请求的是吧 

2004-06-01 15:02:24 Jackey
?

2004-06-01 15:02:26 斜阳
是的

2004-06-01 15:03:14 烟灰缸
这次的主题是:DLL规则层如何接收服务器的数据,又如何交回给服务器。

2004-06-01 15:04:07 斜阳
完全正确,请开始吧

2004-06-01 15:04:36 烟灰缸
斜阳开个头好不,这次也  你的精彩解释呢。

2004-06-01 15:05:24 斜阳
还是你先来吧,不要客气了,我正启动Delphi呢

2004-06-01 15:06:03 烟灰缸
请大家打开swServer2.prj 和 dmDefault.prj

2004-06-01 15:10:32 烟灰缸
    function Operation(var Data, Msg: OleVariant): WordBool; stdcall;
    procedure LoadOleParam(const Param: OleVariant); stdcall;

2004-06-01 15:10:49 烟灰缸
unit dmBaseModule;

2004-06-01 15:11:11 烟灰缸
上次有讲到了这里了,对不?

2004-06-01 15:11:24 斜阳
讲了以部分

2004-06-01 15:12:27 烟灰缸
有谁不清楚这两个的吗?

2004-06-01 15:12:49 断翅
就从Operation和LoadOleParam开讲吧
 
2004-06-01 15:13:35 烟灰缸
我重习复习这两点。

2004-06-01 15:14:45 银狼
怎么这里只有声名没有函数体啊

2004-06-01 15:14:58 Jackey
接口

2004-06-01 15:15:16 断翅
在dmBaseModuleImp中实现

2004-06-01 15:15:28 斜阳
我有一个疑问啊,你在中转服务器中没有使用过
LoadOleParam
为什么说是 LoadOleParam 函数将参数传入到了业务规则动态库了呢?

2004-06-01 15:16:49 断翅
if not VarIsNull(Param) then FParams.LoadFromOle(Param);

2004-06-01 15:17:08 烟灰缸
LoadOleParam是相对于旧版本来说,新版本并不用,这里就略过算了。

2004-06-01 15:17:26 斜阳
不对啊,这个是 FParams.LoadFromOle
不是接口中的方法啊

2004-06-01 15:17:55 烟灰缸
最重要的入口是 function Operation(var Data, Msg: OleVariant): WordBool; stdcall;

2004-06-01 15:18:27 断翅
Result := ActionList(CmdIndex, Data, Msg);
这怎么理解?

2004-06-01 15:19:10 烟灰缸
慢慢来,莫急,好不?N

2004-06-01 15:19:19 斜阳
还有,在DataServer_form中 FParams 是作什么的呢?

2004-06-01 15:20:04 烟灰缸
unit DataServer_form;

    Result := FdmModule.Operation(Data, Msg);
 

2004-06-01 15:20:37 烟灰缸
也就是说,服务器调用DLL,只有用到一个方法。

2004-06-01 15:21:03 烟灰缸
现在,我们看看DLL是怎么去回应它的。

2004-06-01 15:21:18 Jackey
wait.

2004-06-01 15:21:24 Jackey
  if ServiceState = srStart then
    begin
      try
        FdmModule := CreateModule(FBaseService, ModuleIndex);
        FdmModule.Module := ModuleIndex;
      except
        on E: Exception do
          begin
            Result := False;
            Msg := '服务器出错:无法建立数据模组,' + E.Message;
            exit;
          end;
      end;
    end
  else
    begin
      Msg :2

 

2004-06-01 15:34:18 斜阳
中转服务器将一个 IBaseService 接口传给业务规则层的引出函数 CreateDataModule
然后业务规则层就可以操作在中转服务器中创建的一些数据集啊、事务啊什么的
对吧

2004-06-01 15:34:36 烟灰缸
对。

2004-06-01 15:35:38 斜阳
所以说,中转服务器在调用业务规则动态库之前要先    FBaseService.Reset;
然后再
    Result := FdmModule.Operation(Data, Msg);
 

2004-06-01 15:35:51 烟灰缸

2004-06-01 15:37:12 斜阳
在 Operation 函数中的Data包含着从客户端来的请求信息,这些信息会在业务规则动态库(dmDefault.dll)中被合理地使用

2004-06-01 15:37:25 烟灰缸
正确。

2004-06-01 15:37:39 烟灰缸
Data不对

2004-06-01 15:38:10 斜阳
请解释

2004-06-01 15:38:24 烟灰缸
Data有几重意思,但不是客户端来的请求信息。

2004-06-01 15:38:58 烟灰缸
unit dmBaseModule;

    procedure ReceiveDataWithDefault; stdcall;
    procedure ReceiveDataWithCustom; stdcall;
    procedure ReceiveDataWithResult; stdcall;
    procedure ReceiveDataWithNoData; stdcall;
 

2004-06-01 15:39:08 烟灰缸
Data跟这里有关。

2004-06-01 15:39:20 斜阳
噢,是的,看错了,是FParams吧

2004-06-01 15:39:38 烟灰缸
对,是FParams

2004-06-01 15:40:09 斜阳
现在有个问题,业务层是如何知道客户端穿来的信息呢?

2004-06-01 15:40:54 烟灰缸
unit dmBaseModule;
    property Params: IHMOleVariant read GetParams;
 

2004-06-01 15:41:33 烟灰缸
BaseService接口提供个这个接口,它可以读取客户端的参数。

2004-06-01 15:42:31 烟灰缸
也就是说,业务层要Client的参数,就从BaseSerivce.Params中拿。

2004-06-01 15:43:01 烟灰缸
请斜阳继续。

2004-06-01 15:44:06 斜阳
比如吧,客户端说,我给我一斤二锅头酒,然后中转服务器就找啊,找到卖酒的商店了,于是它就对酒店说,有人要买酒,赶紧营业!但是客户写的要买多少酒的纸条?中转服务器是怎么传给酒店的呢?

2004-06-01 15:44:44 斜阳
看看 TBaseService 类的实现吧

2004-06-01 15:45:12 斜阳
在 dmBaseService 单元中有 TBaseService 的实现

2004-06-01 15:45:25 烟灰缸
BaseSerivce.Params['酒数']:=多少斤

2004-06-01 15:45:48 斜阳
大家找一下这个单元中的 TBaseService 类,然后看看 TBaseService 类的 Create方法是如何作的

2004-06-01 15:46:08 银狼
inherited Create;
  FParent := AOwner;
  FReceiveDataType := rdNoData;
  FOle := TBaseOle.Create(AOwner);

2004-06-01 15:46:35 斜阳
在 Create 方法中,有一句比较重要(对传递客户请求来说的)
  FParent := AOwner;
 

2004-06-01 15:47:03 银狼
不太容易联系上啊

2004-06-01 15:47:17 斜阳
这个AOwner是什么呢?一个TComponent
再看看是哪里创建了这个TBaseService?

2004-06-01 15:47:39 烟灰缸
FParent = TDataServer2

2004-06-01 15:48:13 斜阳
通过查找,发现在这里
DataServer_form 单元的 TDataServer2类的 Create方法
大家找到这里

2004-06-01 15:48:54 斜阳
这个过程中有一句
  FBaseService := TBaseService.Create(Self);
原来TDataServer2将自身传给了TBaseService

2004-06-01 15:48:55 烟灰缸
  FBaseService := TBaseService.Create(Self);
 

2004-06-01 15:49:29 斜阳
而TDataServer2类中有一个比较关键的成员
FParams

2004-06-01 15:50:03 斜阳
我想大家可能还记得
    FParams.Clear;
    if not VarIsNull(Param) then FParams.LoadFromOle(Param);

2004-06-01 15:50:29 银狼
能给出类的成员代表的详细信息吗?

2004-06-01 15:50:48 银狼
记得,刚讲的

2004-06-01 15:50:57 斜阳
在调用
    Result := FdmModule.Operation(Data, Msg);
之前,先将客户传来的请求通过
FParams.LoadFromOle(Param)
方入到FParams中了

2004-06-01 15:51:03 烟灰缸
这里的FParams.Clear就是清除了客户的参数。

2004-06-01 15:51:12 烟灰缸

2004-06-01 15:52:13 斜阳
而TBaseService类实现的IBaseService接口有一个方法叫GetParams
大家到dmBaseService单元中找找这个方法是如何实现的就知道参数是怎么传的了

2004-06-01 15:52:30 烟灰缸

2004-06-01 15:53:23 银狼
Result := (FParent as TDataServer2).OleParams;

2004-06-01 15:53:30 斜阳
  Result := (FParent as TDataServer2).OleParams;
这个 OleParams 正是FParams
而前面说过的FParent中存放的就是TDataServer2的一个实例

2004-06-01 15:53:44 烟灰缸

2004-06-01 15:54:23 斜阳
中转服务器将那个客户提交的买酒的纸条给酒店的方法了

2004-06-01 15:54:55 斜阳
是不是比较有趣啊?不好好找找还真找不到

2004-06-01 15:55:31 银狼
我的阅读类的能力有限啊

2004-06-01 15:55:48 烟灰缸
斜阳比较幽默o

2004-06-01 15:56:29 斜阳
刚开始我就奇怪,一个
    Result := FdmModule.Operation(Data, Msg);
调用怎么会传递那么多东西呢?
在调用这个过程之前调用
FParams.LoadFromOle(Param);这个干吗啊?
找了半天,原来如此

2004-06-01 15:56:42 烟灰缸
N

2004-06-01 15:57:30 斜阳
通过 IBaseService 接口,中转服务器向业务逻辑动态库开放了许多的东西

2004-06-01 15:57:52 斜阳
其中的客户请求参数就是一个

2004-06-01 15:58:06 烟灰缸
其实,我的想法是尽量少占用内存,别让参数传来传去。

2004-06-01 15:58:41 斜阳
老大啊,别总我讲啊,你作的程序啊,干吗让我讲啊,我打字这么慢

2004-06-01 15:58:58 烟灰缸
你比较精彩啊,我口才有限。。。。

2004-06-01 15:59:15 斜阳
被你干败了!

2004-06-01 15:59:41 烟灰缸
我哪点打败你了?

2004-06-01 15:59:44 松鼠
    FParams.Clear;
    if not VarIsNull(Param) then FParams.LoadFromOle(Param);和
  Result := (FParent as TDataServer2).OleParams;

Param是客户端传过来,OleParams是服务器自己的参数是吧?

2004-06-01 16:00:24 斜阳
这回大家知道我为什么将直接接收客户端的那个程序叫中转服务层了吧,他确实是在对缝啊

2004-06-01 16:00:27 烟灰缸
OleParams里存放着客户端的Param

2004-06-01 16:00:34 松鼠
OleParams接收客户端Param传过来的值

2004-06-01 16:01:00 烟灰缸
斜阳这么一讲,大家都明白了吧?

2004-06-01 16:01:29 松鼠
明白了一些M

2004-06-01 16:01:55 斜阳
通过
FParams.LoadFromOle(Param)
将客户传来的参数Param,方入到中转服务器中的FParam
在中转服务器中OleParam就是FParam

2004-06-01 16:02:13 烟灰缸

2004-06-01 16:02:15 Locet
英文和中文都懂,意思不太明白,学习ing

2004-06-01 16:02:53 松鼠
客户端如果有请求就只传参数Param参数给服务器,然后服务器就从这个参数的值执行action,是这样子吗?

2004-06-01 16:03:12 烟灰缸

2004-06-01 16:03:57 断翅
这样做是为了节约内存,不理解

2004-06-01 16:04:38 烟灰缸
斜阳请继续。

2004-06-01 16:04:51 斜阳
现在,总结一下,客户端通过调用
OpenData方法向服务器发出请求
在OpenData过程中调用了
RemoteServer.AppServer.DataModule(ModuleIndex, vParam, vData, Msg)
也就是中转服务器的DataModule方法

2004-06-01 16:06:01 松鼠
先说一下有哪些类,和有哪些方法吧

2004-06-01 16:06:45 斜阳
在中转服务器的DataModule方法中,先通过ModuleIndex激活相关的业务规则动态库(注意啊,是激活,不是加载,加载的过程在中转服务器启动的时候就完成了)

2004-06-01 16:07:04 烟灰缸

2004-06-01 16:07:06 松鼠
continue

2004-06-01 16:07:41 斜阳
这个ModuleIndex就是客户传过来的,就好比是“我要买酒的讯号”

2004-06-01 16:08:06 烟灰缸
也就是说,指定了是要“酒”而不是其它的。

2004-06-01 16:08:40 斜阳
中转服务器,看到这个信号后,先到它知道的(已经加载的)业务规则中找找,看看有没有酒店

2004-06-01 16:08:55 斜阳
也就是服务器中的CreateModule函数了

2004-06-01 16:08:58 烟灰缸
正确。

2004-06-01 16:10:13 斜阳
通过查找,发现有酒店,好吧,先把酒店的地址啊、联系电话啊、联系人啊什么的放在FdmModule保存一下吧

2004-06-01 16:11:39 烟灰缸
对。

2004-06-01 16:13:47 斜阳
中转服务器找到要找的了,下一步是要让酒店干活了,于是就把客户传过来的具体要求(Param)先存个档FParams.LoadFromOle(Param),然后打电话给酒店(FdmModule.Operation(Data, Msg)),赶紧营业。于是酒店就看看服务器存档的那份请求是什么,然后提供服务了

2004-06-01 16:14:18 烟灰缸
对?

2004-06-01 16:15:41 银狼
为什么不直接去买,还要中转?

2004-06-01 16:16:23 烟灰缸
因为客户端是老大,中转服务器是保姆。

2004-06-01 16:16:55 斜阳
现在进行的就是这么多了。
感觉DataServer2就像个中介差不多
当这个中介营业的时候,他先把所有它知道的服务(酒店啊、洗浴中心啊什么的)全摆出来等着客户来请求,如果哪个客户来请求了,就激活哪个“娱乐场所”,或者告诉客户你的要求太过分了,不给你提供服务!
 

2004-06-01 16:16:56 银狼
是不是不用保姆,内存的开销就大?

2004-06-01 16:17:45 烟灰缸
斜阳正确。E

2004-06-01 16:18:06 斜阳
中介的好处还是有的,当然,要是你租个房子找个工作什么的不通过中介也能找到,但是你要跑好多的冤枉路的噢

2004-06-01 16:18:48 烟灰缸
DataServer2不只是中介,也还是供应商(相对酒店DLL来讲).

2004-06-01 16:20:25 斜阳
其实三层的好处在于所有的业务逻辑都在中间层上。
打个比方说吧,两层的结构就好像是所有的酒店啊宾馆啊都是为你一个人开的(每台机器上都有业务逻辑),一个人对应一套全套的服务

2004-06-01 16:21:11 烟灰缸
o

2004-06-01 16:22:34 断翅
现在可以讲讲Result := FdmModule.Operation(Data, Msg);

2004-06-01 16:22:53 松鼠
agree

2004-06-01 16:23:04 斜阳
有多少个客户就有多少套服务,那么现在问题来了,政府(政府就和客户业务要求差不多了)要求啊,现在所有的娱乐场所都不许播放不健康的东西啊!现在能播放的娱乐场所赶紧处理啊,那你就必须一个客户一个客户地跑,去告诉这个通知

2004-06-01 16:24:17 烟灰缸

2004-06-01 16:24:26 松鼠
continue

2004-06-01 16:24:44 斜阳
但是,三层结构就好比所有的服务场所我一个人来管,谁要什么服务跟我说,我安排你,这下好了,政府有什么风吹草动的跟我一个人说就是了,顾客就不用打扰你们的好梦了

2004-06-01 16:25:15 烟灰缸
Yes`U

2004-06-01 16:25:40 断翅
还是继续吧

2004-06-01 16:25:41 斜阳
想想现在的商业运营模式,是不是比较接近三层结构啊?

2004-06-01 16:25:50 烟灰缸
对。

2004-06-01 16:26:16 斜阳
存在就是合理的,所以三层的结构要比两层的结构相对合理些

2004-06-01 16:26:24 松鼠
‘我’指的是什么?

2004-06-01 16:26:31 烟灰缸
我上次那个“办公室管理”也是差不多的意思。

2004-06-01 16:26:36 Locet
中间层

2004-06-01 16:26:42 斜阳
当然就是中转服务层了

2004-06-01 16:27:11 松鼠
哦,继续

2004-06-01 16:27:12 烟灰缸
中间层=中转服务层+规则层

2004-06-01 16:27:25 Locet
斜阳说得通俗容易懂

2004-06-01 16:27:37 斜阳
当然了,烟灰缸权利大,让我兼职干了点别的(刚刚他说的啊,中间层并不只干中介啊)

2004-06-01 16:27:49 松鼠
但是还没说到代码

2004-06-01 16:28:06 烟灰缸
对,来个掌声给斜阳。?

2004-06-01 16:28:23 银狼
?

2004-06-01 16:28:26 dana
有多少个客户就有多少套服务
这是对二层而言,还是三层而言?

2004-06-01 16:28:28 斜阳
还有谁对为什么使用三层而不是两层存在疑问?

2004-06-01 16:28:38 斜阳
两层了

2004-06-01 16:29:18 Locet
缸哥也说点啊~~别YES,对的

2004-06-01 16:30:04 烟灰缸
Locet 我的口才太差了,说了总是有些不懂。y

2004-06-01 16:30:16 斜阳
当然了,有些情况比较例外,比如你是很有钱的啊,而且世界就你一个消费者,那么所有的经营场所都围着你转是正常的。
(你就几个客户,而且还比较集中,那两层三层就无所谓了)

2004-06-01 16:30:55 断翅
现在该讲讲“酒店”里是如何操作了吧

2004-06-01 16:31:00 烟灰缸
对,两层和三层是看情况的,不一定死要三层。

2004-06-01 16:31:32 斜阳
是的,请 烟灰缸 老师说说业务逻辑层吧

2004-06-01 16:32:00 dana
太精彩了!X

2004-06-01 16:32:02 烟灰缸
别老师了,惭愧啊。

2004-06-01 16:33:03 松鼠
不会的J

2004-06-01 16:33:10 烟灰缸
我们看看"酒店"的作业情况。

2004-06-01 16:33:14 银狼
? 你们都很好


//---------------业务逻辑部分-----------------------
2004-06-01 16:34:38 烟灰缸
unit dmBaseModuleImp;
  TBaseDataModule = class(TInterfacedObject, IBaseDataModule)
 
2004-06-01 16:34:57 烟灰缸
先看看它的作业方式。

2004-06-01 16:35:05 斜阳
具体的业务逻辑我没有详细跟踪过,这个恐怕我就说不明白了

2004-06-01 16:35:19 松鼠
能不能先把其中的类大概重点的说一下?

2004-06-01 16:35:33 烟灰缸
没关系,我学学你的方式。

2004-06-01 16:35:48 斜阳
还是先说说那两个导出函数吧,这样能连贯上

2004-06-01 16:36:13 烟灰缸
就是最前面两个CreateXXX?

2004-06-01 16:36:18 斜阳
是的

2004-06-01 16:36:30 烟灰缸
好。

2004-06-01 16:36:55 烟灰缸
function CreateDataModule(const BaseService: IBaseService): IBaseDataModule; stdcall;
function CreateDataModuleInfo: IDataModuleInfo; stdcall;
 

2004-06-01 16:37:03 斜阳
我帮你说说我看过的部分,不地方的地方你接着说,如何

2004-06-01 16:38:19 烟灰缸
这两个函数必须Experts,而且,必须实例化IBaseDataModule和IDataModuleInfo

2004-06-01 16:38:34 斜阳
先看看dmDefault工程的dmDefault单元
在这个单元中,我们可以看到有两个导出函数exports
  CreateDataModule, CreateDataModuleInfo;

2004-06-01 16:38:56 斜阳
大家找到了吧

2004-06-01 16:39:18 烟灰缸
因为,这两个接口相当于是“规则标准书”

2004-06-01 16:39:56 烟灰缸
function CreateDataModule(const BaseService: IBaseService): IBaseDataModule; stdcall;
begin
  Result := TdmDefault.Create(BaseService);
end;

2004-06-01 16:40:13 斜阳
我们看其中的CreateDataModule函数
这个函数创建了TdmDefault类的一个实例,并将创建的这个实例以IBaseDataModule接口的形式返回

2004-06-01 16:40:58 烟灰缸
TdmDefault.Create(BaseService);就是把"规则标准书"实际化了。

2004-06-01 16:41:33 斜阳
这个函数在哪里被调用过呢?
看看swServer2工程中的 
DataServer_form单元

2004-06-01 16:42:02 烟灰缸
再看看,它是怎么被Create的。

2004-06-01 16:42:04 烟灰缸
unit dmBaseModuleImp;

2004-06-01 16:43:25 烟灰缸
TdmDefault 的基类是TBaseDataModule

2004-06-01 16:43:44 烟灰缸
所有,先看看TBaseDataModule.Create

2004-06-01 16:44:07 烟灰缸
constructor TBaseDataModule.Create(const BaseService: IBaseService);
begin
  inherited Create;
  Service := BaseService;
  Sql := THMSqlEx.Create;
  StoreProc := THMSqlStoreProcEx.Create;
  MsgList := TStringList.Create;
  Sql.BaseService := BaseService;
  StoreProc.BaseService := BaseService;
end;
 

2004-06-01 16:44:49 烟灰缸
Service := BaseService;先保存BaseService接口到本地。

2004-06-01 16:45:08 烟灰缸
  Sql := THMSqlEx.Create;
  StoreProc := THMSqlStoreProcEx.Create;
这两个是管理SQL语句的。

2004-06-01 16:45:27 烟灰缸
MsgList是信息管理,以后的版本有用。

2004-06-01 16:45:30 dana
先保存BaseService接口到本地。
有什么用处?

2004-06-01 16:45:57 烟灰缸
因为所有的派生类都要用到Service

2004-06-01 16:46:20 烟灰缸
  Sql.BaseService := BaseService;
  StoreProc.BaseService := BaseService;

2004-06-01 16:47:50 烟灰缸
意思是让Sql和StoreProc这两个SQL管理器和TBaseDataModule一起共同BaseService

2004-06-01 16:48:08 烟灰缸
这一段,大家有不明白的吗?

2004-06-01 16:50:39 斜阳
单纯从代码上说,应该明白了

2004-06-01 16:51:01 松鼠
BaseDataModule.Create 在哪有调用到?

2004-06-01 16:51:07 烟灰缸
意思就不明白了。。。。。。。。。。。y

2004-06-01 16:51:26 烟灰缸
DLL最开始的时候有用到。

2004-06-01 16:51:42 斜阳
随着问题的深入,应该会明白的

2004-06-01 16:51:43 松鼠
哦,我看看

2004-06-01 16:52:07 Jackey
ok

2004-06-01 16:52:46 烟灰缸
我们看看中转服务器所调用它的方法Operation(var Data, Msg: OleVariant).

2004-06-01 16:53:24 烟灰缸
大家看看
function TBaseDataModule.Operation(var Data, Msg: OleVariant): WordBool;
的实现方法。

2004-06-01 16:54:21 烟灰缸
  try
    CmdIndex := Service.Params.Action;
    Result := ActionList(CmdIndex, Data, Msg);
    StoreProc.Clear;
    SQL.Params.Clear;
 

2004-06-01 16:54:26 银狼
wordbool是个什么类型啊

2004-06-01 16:54:30 烟灰缸
unit dmBaseModuleImp;

2004-06-01 16:54:41 烟灰缸
WordBool = Boolean

2004-06-01 16:55:13 银狼
区别呢?

2004-06-01 16:56:02 烟灰缸
CmdIndex是指派小规则的指令号,它在ActionList中用到。

2004-06-01 16:56:11 烟灰缸
没有区别,一样的。

2004-06-01 16:56:17 Jackey
The four predefined Boolean types are Boolean, ByteBool, WordBool, and LongBool. Boolean is the preferred type. The others exist to provide compatibility with other languages and operating system libraries.
A Boolean variable occupies one byte of memory, a ByteBool variable also occupies one byte, a WordBool variable occupies two bytes (one word), and a LongBool variable occupies four bytes (two

2004-06-01 16:56:52 烟灰缸
    Result := ActionList(CmdIndex, Data, Msg);
    StoreProc.Clear;
    SQL.Params.Clear;
 

2004-06-01 16:57:25 烟灰缸
从这里可以看到,它调用了ActionList

2004-06-01 16:59:01 烟灰缸
所有的派生规则必须Override ActiveList,因为基类必须调用它。

2004-06-01 16:59:51 烟灰缸
unit dmDefaultModule;
我们看看TdmDefault是如何实现它的。

2004-06-01 17:00:01 烟灰缸
    function ActionList(CmdIndex: integer; var Data, Msg: OleVariant): WordBool; override;
 

2004-06-01 17:00:19 烟灰缸
  case CmdIndex of
    acOpenView: Result := OpenView(Data, Msg);
    acOpenStoreProc: Result := OpenStoreProc(Data, Msg);
    acExecute: Result := Execute(Data, Msg);
    acOpenSql: Result := OpenSql(Data, Msg);
    acUpdateWithDelta: Result := UpdateWithDelta(Data, Msg);
    acUpdateWithDRI: Result := UpdateWithDRI(Data, Msg);
    acUpdateWithMCDelta: Result := UpdateWithMCDelta(Data, Msg);
    acUpdateWithMCDRI: Result := UpdateWithMCDRI(Data, Msg);
  else
    Result := inherited ActionList(CmdIndex, Data, Msg);
  end;
 

2004-06-01 17:01:13 烟灰缸
很明显,ActionList跟据CmdIndex做了指派。

2004-06-01 17:01:43 烟灰缸
并对应到自己本身的一个个Action

2004-06-01 17:01:58 烟灰缸
这一段大家能明白吗?

2004-06-01 17:02:30 银狼

2004-06-01 17:02:43 烟灰缸
哪不明白?

2004-06-01 17:03:11 银狼
acOpenView这些是什么?

2004-06-01 17:03:29 松鼠
 CmdIndex的值

2004-06-01 17:03:41 银狼
知道,什么意思呢?

2004-06-01 17:04:28 烟灰缸
CmdIndex是客户指定的,他们都在ModuleIndex.pas中定义。

2004-06-01 17:04:44 银狼
那我自己看看吧

2004-06-01 17:05:08 烟灰缸
斜阳帮我补充一下好不?

2004-06-01 17:06:17 斜阳
我知道的也这么多啊,在业务逻辑层有些动西没有源代码,我跟不进去,所以只是知道个大概,重点还都被你说了

2004-06-01 17:06:17 银狼
哦?我没有找到啊

2004-06-01 17:07:08 Jackey
找什么?
function TdmDefault.OpenView(var Data, Msg: OleVariant): WordBool;
var
  i: integer;
begin
  LoadFromStore(Ole.ViewIndex, slSql);
  try
    for i := 1 to Sql.Params.Count do
      begin
        if Ole.FindField(Sql.Params.Items[i - 1].Param) <> nil then
          Sql.Params.ParamValue[Sql.Params.Items[i - 1].Param] := Ole[Sql.Params.Items[i - 1].Param];
      end;
    Service.Q2


2004-06-01 17:07:28 银狼
ModuleIndex.pas

2004-06-01 17:07:28 松鼠
TdmDefault和TBaseDataModule这两个类什么关系?

2004-06-01 17:07:53 烟灰缸
TBaseDataModule 是TdmDefault是父亲

2004-06-01 17:08:02 斜阳
反正我个人觉得,看一个人的程序,看他怎么作的没什么意义,主要是看他的思想,他为什么要这样呢?知道他的思想后,具体的实现就不是很重要了

2004-06-01 17:08:08 松鼠
哦,刚看到

2004-06-01 17:08:19 烟灰缸

2004-06-01 17:08:41 银狼
是啊,所以我还在听

2004-06-01 17:09:02 松鼠
function TBaseDataModule.ActionList(CmdIndex: integer; var Data, Msg: OleVariant): WordBool;
begin
  Msg := format(' SΤ i H磅     R O(%d)', [CmdIndex]);
  Result := False;
end;
这个作什么?

2004-06-01 17:09:16 松鼠
哦,返回信息

2004-06-01 17:09:53 斜阳
在规则层中,使用的比较传统的方式实现动态的功能(基类定义逻辑,子类实现逻辑)

2004-06-01 17:10:15 烟灰缸

2004-06-01 17:10:26 松鼠

2004-06-01 17:10:56 斜阳
看看dmBaseModuleImp 单元的 TBaseDataModule
基类

2004-06-01 17:11:13 银狼
可以按客户的需要而声名实例么?

2004-06-01 17:11:22 烟灰缸
可以

2004-06-01 17:12:08 银狼
在实例中添加特殊的需要也行是吧

2004-06-01 17:12:10 斜阳
在这个类的Create方法中保存了中转服务器传来的接口,并创建了一些可能会用到的东西

2004-06-01 17:12:24 烟灰缸

2004-06-01 17:12:53 银狼
接口  这个概念我不懂,也不知道如何使用

2004-06-01 17:13:09 斜阳
然后是刚刚讨论了半天的 Operation 函数

2004-06-01 17:13:10 松鼠
我也不懂

2004-06-01 17:13:46 斜阳
如果实在不知道接口,那你把接口当做一个抽象类好了

2004-06-01 17:13:47 银狼
有系统的教材讲接口吗?给我个看看

2004-06-01 17:14:10 银狼
可定义和使用就有困难了

2004-06-01 17:14:15 烟灰缸
<<Delphi COM+深入编程>>

2004-06-01 17:14:28 银狼
哪里有下载啊

2004-06-01 17:14:40 烟灰缸
我是买书的。

2004-06-01 17:15:45 断翅
那抽象类和接口有什么区别吗,只考虑单继承的情况下

2004-06-01 17:16:29 松鼠
IBaseService接口起到什么作用

2004-06-01 17:16:58 烟灰缸
前面已经讲过了。

2004-06-01 17:18:56 松鼠
我再看看,继续吧

2004-06-01 17:19:20 斜阳
在 Operation 方法中调用了一个虚方法ActionList
这个虚方法要干什么,子类说了算

2004-06-01 17:19:33 断翅
没人回答我的问题F

2004-06-01 17:19:34 烟灰缸

2004-06-01 17:20:08 烟灰缸
断翅 看看COM+的书,理面有说。

2004-06-01 17:20:34 斜阳
接口好多语言都支持,抽象类就不一定了

2004-06-01 17:21:18 断翅
Thanks

2004-06-01 17:21:46 斜阳
接口只是定义了一个协议

2004-06-01 17:22:31 烟灰缸
对,协议的实现方法由类去实现。

2004-06-01 17:22:44 断翅
抽象类也是定义方法而不实现啊

2004-06-01 17:22:54 斜阳
在 Operation 方法中调用 ActionList 方法就是个协议,所有的子类都要这么作

2004-06-01 17:23:37 斜阳
按照语法上说,抽象类中可以包含数据,但是接口就不行

2004-06-01 17:24:28 烟灰缸
在 Operation 方法中调用 ActionList 方法就是个协议(这个协议函意上不等于接口的协议)

2004-06-01 17:26:13 斜阳
就好比人,规定了当被问到问题的时候(Operation)必须回答(ActionList)
至于使用什么语言,怎么回答,那具体的人就具体分析了,有的人用英语,有的人用汉语

2004-06-01 17:26:34 烟灰缸

2004-06-01 17:27:31 斜阳
回答的方式,就交给子类作吧
就好像 人 是基类,中国人、英国人 是人的子类,在回答问题的方式上是不一样的

2004-06-01 17:28:35 烟灰缸
TBaseDataModule 是 人( 是基类) TdmDefault 是中国人(是人的子类)

2004-06-01 17:28:58 斜阳
是这样的

2004-06-01 17:29:03 松鼠
  TBaseService = class(TSafeInterfacedObject, IBaseService)
TBaseService 和 IBaseService什么关系?客户端也有一个IBaseService接口,两个怎么联系?

2004-06-01 17:30:04 烟灰缸
客户端哪来的IBaseService?

2004-06-01 17:30:11 斜阳
当我们在人这个层面上规定了必须是一问一答的方式回答问题时,就是定义了规则,不管哪国人,必须这样作

2004-06-01 17:30:28 松鼠
constructor TBaseDataModule.Create(const BaseService: IBaseService);
这个啊

2004-06-01 17:30:40 斜阳
TBaseService 实现了 接口的约定

2004-06-01 17:31:16 烟灰缸

2004-06-01 17:31:38 松鼠
怎么约定,比如呢

2004-06-01 17:32:08 斜阳
看看IBaseService接口的定义,那里面定义的东西就是约定

2004-06-01 17:32:22 松鼠
好的

2004-06-01 17:33:19 烟灰缸
从上面的谈话看是,可能是有一些朋友对接口不太了解。

2004-06-01 17:33:49 松鼠
定义的东西大概知道,但还是不明白具体怎么去操作约定?

2004-06-01 17:35:07 烟灰缸
可能想象把接口当成是抽象基类

2004-06-01 17:35:17 松鼠
好的

2004-06-01 17:36:15 烟灰缸
这个三层程序包函了大量的接口,也不怪得大家看晕了,我也晕了。?

2004-06-01 17:36:25 斜阳
比如啊,业务层通过什么方式开启一个事务呢?
接口中这样定义
    procedure BeginTrans; stdcall;
那通过什么方式提交一个事务呢?
    procedure CommitTrans; stdcall;

至于如何开启事务和提交事务,那是由实现接口的类决定的

2004-06-01 17:36:50 烟灰缸

2004-06-01 17:37:26 斜阳
我在实现中,可以用ADO,我也可以用BDE
甚至是直接操作API都可以

2004-06-01 17:37:43 烟灰缸
是都可以。

2004-06-01 17:40:50 烟灰缸
看看也没多少时间了,下一课的主题是:ActiveList的Action的工作方式。时间是星期四下午3点。

2004-06-01 17:41:14 银狼
是控件么?

2004-06-01 17:41:17 斜阳
好的,我整好要走了,再见

2004-06-01 17:41:30 银狼
再见

2004-06-01 17:41:32 烟灰缸
不是控件。是这个三层程序。

2004-06-01 17:41:48 银狼
哦,幸好问一下

2004-06-01 17:42:13 烟灰缸
记得时间:星期四下午3点。大家下次见。?

posted @ 2004-09-11 14:54  D10.天地弦  阅读(977)  评论(0编辑  收藏  举报