LibCRB_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+体系中,这倒不是上一页 [1] [2] [3] 下一页 |