分享
 
 
 

《关于VisiBroker For Delphi的使用》(4)

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

《关于VisiBroker For Delphi的使用》

-CORBA技术实践(一)

宜昌市中心人民医院 赵普昉

email: 3boy@sohu.com

4、实例设计与分析

上一次我想大家介绍了一个在CORBA中使用Pooler的小程序,这段代码中使用了较为高级的编写方法,在分析这个实例之前,我想和大家谈一点设计工具的应用,当然我会在本文的后续文章中深入探讨关于这些辅助手段的应用,在这里我只想简要的描述一下,为正真的工程项目中实现CORBA技术做好相应的知识储备。

前面我介绍了接口描述语言(IDL)的一些较为基础语言要素,如果只是在Delphi中开发实际的基于VisiBroker 的ORB多层应用体系的基本应用可以大胆的说已经够用了(如果有人反对我不介意),CORBA是一一个不断补充发展的标准,而且每种ORB产品又会对CORBA进行自己的描述,所以前面的一些IDL只是有一部分和OMG的定义有一定的区别,但是这不会影响到我们理解CORBA,当然必须说明的是前面的IDL描述都是完全符合VisiBroker的规范的。在C/S模式的程序设计之中,我们中绝大部分人是不会去考虑接口设计的,偶尔的出现也不会是采用我们开发多层系统这样的模式,所以刚刚接触多层系统的程序员要付出比C/S模式下设计大的多地精力来设计它,而且会拖延开发的周期,我一直在思考一个问题能不能避免这样的事情呢?或者说去谋求一个好的方法来改进我们的设计呢?在我看来拖延工期的问题主要表现在我们对于接口的确定上,接口的不确定因素体现在增加接口,修改接口,废止接口等等诸多问题上,设计接口我觉的类似与我们在设计ER图中的实体间的关系一样,如何平衡【服务――-中介―――客户】三者之间的关系是多层的首要问题,也是使得我们反复的罪魁祸首,在这里我想向大家推荐强大的Rational家族系列产品(Rose,SODA,ClearCase…..)我们可以使用这样的一些辅助工具来缩短我们的反复频率,在问题的分解中明确接口的设计方向与设计原则,对于拥有微软企业版开发套间的朋友可以利用Virtual Moduler工具来设计(这个工具是微软捆绑的ROSE产品,是一个标准的多层体系)在这里我不对如何使用他们来设计CORBA的接口进行描述,原因只有一个这是一个高级课题不属于<VisiBroker for Delphi>的范畴之中,我会在《面向CORBA的设计实践》中与大家共同探讨。

好了闲话就聊到这里,下面开始正体。

记得我在本文的第一小节中提到过CORBA DataMoudel Object,如果使用过这个对象的朋友一定清楚的了解单线程模式与多线程模式,也就是CORBA 3.3为大家提供了两种来至于TDataMoudel对象,进行的整体的封装,然而现在的CRB4.0为程序员提供了更大的灵活性

让我们自己来编写这样的两种不同的对象,显然后者可以让我们更广泛的扩展应用面,上次的例程就是一个多线程模式的例子,在讲解多线程模式之前我想还是让我们来看一下单线层模式的实例:

/*IDL*/

module TypeLibCRB

{

interface InterfaceCRB;

interface InterfaceCRB

{

any GetSQLData(in wstring Script, in boolean ExecutOrActive);

};

//定义一个发送客户执行的SQL,返回一个any类型

};

//XXX_Impl.pas

interface

uses

SysUtils,

CORBA,

TypeLibCRB_i,

TypeLibCRB_c

;

type

TInterfaceCRB = class;

TInterfaceCRB = class(TInterfacedObject, TypeLibCRB_i.InterfaceCRB)

protected

public

constructor Create;

function GetSQLData ( const Script : WideString;

const ExecutOrActive : Boolean): Any;

end;

implementation

uses UmCRBServer, UnCRBServer;

constructor TInterfaceCRB.Create;

begin

inherited;

end;

function TInterfaceCRB.GetSQLData ( const Script : WideString;

const ExecutOrActive : Boolean): Any;

begin

Form1.Memo1.Lines.Text:=Script;

Result:=DataMCRB.GetData(Script,ExecutOrActive);

//调用TDataMoudel实例的方法请注意这个地方只有一个TDataMoudel实例

//下面的程序中会描述这个实例的方法定义

end;

initialization

end.

/********************/

/*动态创建数据实例的操作*/

unit UmCRBServer;

interface

uses

SysUtils, Classes, DB, DBTables,Provider;

type

TDataMCRB = class(TDataModule)

DatabCRB: TDatabase;

QueryCRB: TQuery;

DataSetPCRB: TDataSetProvider;

private

{ Private declarations }

public

function GetData(Script:String;ExecuteOrActicve:boolean):OleVariant; { Public declarations }

end;

var

DataMCRB: TDataMCRB;

function RunSQL(QueryX:TQuery;Script:String;ExecuteOrActive:boolean):boolean;

implementation

//这个代码中没有使用Session,也没有对事务进行控制,下一章节会给出一个使用Session的//例程,想一想这个方法的应用会有什么有点和缺点,如果愿意谈一谈請将您的想法发往我得//信箱

{$R *.dfm}

function RunSQL(QueryX:TQuery;Script:String;ExecuteOrActive:boolean):boolean;

begin

Result:=false;

with QueryX do

begin

if Active then Active:=false;

SQL.Clear;

SQL.Text:=Script;

if ExecuteOrActive then

ExecSQL else

Active:=true;

if not IsEmpty then

Result:=true;

end;

end;

//这段代码我不讲解

{ TDataMCRB }

function TDataMCRB.GetData(Script: String;

ExecuteOrActicve: boolean):OleVariant;

var

MyQry:TQuery;

MyPrv:TDataSetProvider;

begin

try

MyQry:=TQuery.Create(self);

MyPrv:=TDataSetProvider.Create(self);

MyQry.DatabaseName:=DatabCRB.DatabaseName;

//注意如果使用TDataBase对象請将ShareHandle设为True;

MyPrv.DataSet:=MyQry;

if RunSQL(MyQry,Script,ExecuteOrActicve) then

Result:=MyPrv.DATA;

finally

MyQry.Free;

MyQry:=nil;

MyPrv.Free;

MyPrv:=nil;

end;

end;

//动态创建数据集和数据提供者对象,在调用接口将数据返回给Client后释放动态创建的两//对象。这样可以避免在单线模式下客户端持久的拥有接口后的对象。

end.

/*****************************************/

/初始化CORBA实例,主单元

unit UnCRBServer;

interface

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,

Corba, TypeLibCRB_c, TypeLibCRB_i, TypeLibCRB_impl, TypeLibCRB_s,

StdCtrls;

type

TForm1 = class(TForm)

procedure FormCreate(Sender: TObject);

private

{ private declarations }

protected

{ protected declarations }

MyCRB:InterfaceCRB;

procedure InitCorba;

public

{ public declarations }

end;

var

Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.InitCorba;

begin

CorbaInitialize;

MyCRB:=TInterfaceCRBSkeleton.Create('MyCRBServer',TInterfaceCRB.Create);

BOA.ObjIsReady(MyCRB as _Object);//CORBA服务就绪

end;

procedure TForm1.FormCreate(Sender: TObject);

begin

InitCorba;//初始化调入

end;

end.

/******************************************************/

/客户端程序

nit UnClientMain;

interface

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,

Corba, TypeLibCRB_c, TypeLibCRB_i, Grids, DBGrids, DB, DBClient, StdCtrls;

type

TForm2 = class(TForm)

Edit1: TEdit;

Button1: TButton;

ClientDataSet1: TClientDataSet;

DataSource1: TDataSource;

DBGrid1: TDBGrid;

procedure Button1Click(Sender: TObject);

procedure FormCreate(Sender: TObject);

private

{ private declarations }

protected

/ myCRB:InterfaceCRB;

{ protected declarations }

public

{ public declarations }

end;

var

Form2: TForm2;

implementation

{$R *.DFM}

procedure TForm2.Button1Click(Sender: TObject);

begin

ClientDataSet1.Data:=myCRB.GetSQLData(Edit1.Text,false);

end;

procedure TForm2.FormCreate(Sender: TObject);

begin

myCRB:=TInterfaceCRBHelper.Bind('MyCRBServer','127.0.0.1');

end;

end.

上面的程序让你无法使用ApplyUpdate方法来从客户端更新数据,如果要更新数据必须通过GetSQLData(SQL,True)来更新数据,相对来说客户端将不能使用数据感知类组件来编写插入删除,修改类程序,因为你的中间层的数据集与数据提供者不具有持久性,这就是下面代码使用DMPooler的精妙之处。

//

TDataModuleClass = class of TDataModule; // "class" reference

首先,由于客户请求数目的不确定性,我们必须为可能的请求提供一个用于存放独立实例请求单元的空间量(Pooler Size),假定我们考虑的可能有5个独立请求同时拥有这样持久对象,那么我们可以设定PoolSize=5,注意必须定义在全局的CONST中,因为每个对象是一个独立体,不过里也可以将这样的对象列入到TLIST对象中保存,当然还有更高级的构造方式,这些东西来源于程序员对Delphi的理解程度,例如:你可以将全部的实例使用TCollection类化处理,而不是使用下面的记录类型:

TPooledModule = record

Module: TDataModule;

InUse: Boolean;

end;

当然这个地方使用的比较基础的方式来处理每一个ITEM,这个单元中包含了一个TDataModule实例,何一个表示这个实例是否被起用的开关量(我是这么命名的,当然这仅是基本的表达,而根据业务需求的规则需要自己来定义比此更好的比编写方式,而这个东西同样来源于对于OO概念的理解,和面向对象编程的经验的积累).

当然,由于我们的客户对象的相互独立并确是一个持久的对象,那么也就是告诉我们整个对象池,是一个多线程的架构(如果是初次接触的朋友们最好先去读一下Thread).所以我们必须在对象的构造方法中申明为

constructor TModulePooler.Create;

begin

IsMultiThread := True;

……

end;

如果请求被客户中断,或则实例由于异常而停止我们必须将这个实例终止,释放实例对象:

procedure TModulePooler.FreeModule(DataModule: TDataModule);

var

I: Integer;

Begin

………

for I := 0 to Length(FModules) - 1 do

if FModules[I].Module = DataModule then

FModules[I].InUse := False;

ReleaseSemaphore(FSemaphore, 1, nil);

……..

end;

那么,创建和释放的方法在我们写好已后,那么我们如何来构造这个单元的实体方法呢?

请看:

function TModulePooler.GetModule: TDataModule;

var

I: Integer;

begin

Result := nil;

if WaitForSingleObject(FSemaphore, 5000) = WAIT_TIMEOUT then

//设定延时响应,假定服务超时,那么我们将引发一个异常类,表示服务器太忙而未能响应请求。

raise Exception.Create('Server too busy');

try

if Length(FModules) = 0 then

//如果这个对象记录数组为空我们将创建这样一个动态的对象记录数组,即创建一个链表,每个对象作为其中的一个单元而存在,当然在实际的开发中我认为这种方法不是最好的,我会采用TStrings或则Tlist以及TCollections来存放单元,具体的使用我会在下一节给出

begin

SetLength(FModules, PoolSize);

for I := 0 to PoolSize - 1 do

begin

FModules[I].InUse := False;

FModules[I].Module := FModuleClass.Create(Application);

end;

end;

for I := 0 to Length(FModules) - 1 do

if not FModules[I].InUse then

begin

FModules[I].InUse := True;

Result := FModules[I].Module;

Break;

end;

finally

FCSect.Leave;

end;

//Check if we ran out of connections

if not Assigned(Result) then

raise Exception.Create('Pool is out of capacity');

end;

在加载时创建

initialization

ModulePooler := TModulePooler.Create;

退出时释放

finalization

ModulePooler.Free;

千万要记住检测对象是否存在,一定要在不再使用的时候释放持久对象,否则就会不断的堆砌,最终溢出哦!

可能是工作的原因,最近总是抽不出太多的时间来写这样的文章,在我看来已后基于C/S的软件将会越来越少,而绝大多数会聚集于微软的COM+体系中,这倒不是说COM+一定比CORBA优秀,而是COM+不要钱,而仅仅是需要一套WIN2000/XP,当然一向已C++为设计语言的朋友们可以参考很多的用C++写的资料,而Delphi的朋友们的资料少的可怜,建议还是学一点C++,我相信“真正的程序员用C++,聪明的程序员用Object Pascal,而大师[绝对优秀的程序师]是没有语言障碍的“,“有条件的用CORBA(因为跨平台),没有条件的用COM+(因为CORBA收费,COM+免费)”.

下一节谈讨更高级的话题(对象定位技术与接口异常处理)

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
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- 王朝網路 版權所有