关于三层结构的企业逻辑怎么构建? 大家解答我之困惑。(100分)

  • 主题发起人 主题发起人 wuisland
  • 开始时间 开始时间
W

wuisland

Unregistered / Unconfirmed
GUEST, unregistred user!
以前公司做的三层结构是在客户端构造SQL,而中间层只是简单的执行。
而且,企业规则也未在中间层定义。我一直都比较困惑这样的方式,
但又不知道怎样来把企业规则放到中间层。
有很多书也是说中间层放企业规则,那怎么放呢?
在中间层怎么来构造SQL呢?
请大家来讨论这个话题。
 
中间层接受客户端传送过来的参数
使用RemoteModule等远程模块通过Dcomconnection等连接控件
将sql语句传送到sql-server执行
中间层存放企业规则的含义我的理解就是将企业规则书写成
中间层的接口函数提供给客户端调用
至于怎么放那就是放接口下咯,呵呵
 
道理是这样的。我也知道,看来用一个简单的例子比较好描述我们的问题。
我们就拿一个简单的销售单来说吧,现在在客户端输入销售单的信息,
怎样来提交呢? 我们是把销售单的各项(如:销售单号及它的字段名)
传递到中间层呢?还是在写好的SQL传递过去呢?
那么,这样看来差别不大。
 
传统的C/S架构的程序中,要么是把业务逻辑以存储过程的形式写在数据库里(业务逻辑被
焊在服务器端),要么是写在客户端,多层结构强调的就是要把业务逻辑写在应用服务器里,
应用服务器就是要与数据库、客房端两者割离,并且位置透明。
Borland的MIDAS技术又提供了一种中间层透明的技术,使得开发者在开发多层结构的程序时,
可以延用以前开发C/S结构程序时的习惯,使用MIDAS技术,以往的C/S程序可以比较容易地
过渡为多层结构的程序。但是,我认为MIDAS技术在提供这种便利时,也使得开发人员很容易
错误地使用MIDAS技术,他们会继续延用以前做C/S结构程序的思维,将更新数据的代码写在
客户端,应用服务器里除了数据对象(包括TDataSet和TDataSetProvider的对象)外,没有
一行代码,也没有业务逻辑对象,业务逻辑又粘在了客户端一边,变成了一种被扭曲了的多
层结构。
我在应用中的划分方法是:
1、客户端:(只做用户界面,不包含任何业务逻辑,要更新数据时,调用业务逻辑对象的
方法,而不是用TClientDataset的Post或ApplyUpdates或Execute一个SQL命令);
2、业务逻辑对象(在服务器端,通过调用数据对象来存取数据,业务逻辑全写在这里面,
封装为一个个的方法,供客户端调用);
3、数据对象(服务器端,不包含业务逻辑,只向业务逻辑对象提供数据来源)。
这样分离后,业务逻辑对象和数据对象可以在一台服务器上,也可以分开来,数据对象与
数据库在一台服务器上(如果与数据库是同一平台的话),如果后面的数据库表结构、业务
逻辑发生变化时,只要接口没有发生变化,客户程序就不用更新,这就意味着可以避开传统
C/S结构程序的一大麻烦:更新客户端程序。
 
对于Sachow的论述,我非常赞同,特别是第二段。我和同事们一般称这种写法是"假三层"。
对于"假三层"的应用程序,它的局限性是显而易见的,但Borland提供的这种MIDAS技术,
就是极大的方便了开发人员以C/S模式来编写三层应用,毕竟,现在的客户端应用程序已经
不再需要安装数据库客户端的库文件,只要一个Midas.DLL就足够了。
企业逻辑,说白了就是服务器满足客户端要"干什么"的要求的集合。比如"提交请假单",客户端
只需要把请假单的收件人,标题,内容等以参数方式调用服务器相应的方法,至于服务器是怎么样做,
根本就不是客户端程序的事了。
但抽象出企业逻辑,是一个比较漫长和细致的过程。
我的意见是如果是赶时间,用"假三层"见效快,而且系统物理结构与真的一样,程序可以以后
改,但最好还是按照Sachow兄的方法,实现真正的三层架构。
 
szf 先生的“假三层”,应该就是我以前公司的开发方式,在客户端把SQL构造好。
Sachow 先生的说法我很赞同,我理解的也是这样。但怎样来构造呢。
如szf 先生的请假单,我们说把请假单的各个字段值都传给中间层,那么也应该把
相应的字段名传给中间层了。不然怎么知道对应哪个字段呢。
 
顺便说下,以前我们在客户端构造SQL,其实也是由程序自己构造,在每个字段对应的
输入框的NAME定义成字段名,然后由程序来构造这些SQL,那么说,我们是不是把这种
方式放到中间层就是呢? 客户端将这些NAME 及对应的值上传就是呢?
 
客户端只需要获得参数。传回中间层。然后由中间层构造商业逻辑。如果有一天,您在
客户端看不见一句SQL。同时,DATAMODULE里面只有极少代码。有这二点。您肯定已在成功
运用MIDAS技术了。我现在做的只需只要一个Midas.DLL就足够了。现在准备注过度到多层结
构客户端不安装客户程序。通过网页调出来。比女人还爽得很。正在实现。应该可以。
加。。。。。您知道,哈。。。。
 
to Sachow,你的说法小弟非常同意,这也正是很多三层书籍上写的。
但小弟有一点不明白:如果我把所有特定的操作都写成方法或函数放在中间层,客户端通过
远程调用中间层的组件,按李维书上写的,这样每次都会连接中间层服务器,我又如何来保
证速度呢?
谢谢!
 
解决了我一直以来的困惑,thanks!
 
如果做三层,现在也不需要在客户端安装程序了。只需要一个MIDAS.DLL文 件。我刚才才试
通。在远程电脑上运行。很爽。
 
我想我现在可能是需要各位老兄再点拨下。
那么到底传递的参数是什么呢?
如果我们只传递去如“更新请假单”,那么中间层就要回掉客户端的数据。
要么就要把数据一起传给中间层,是这样吗?
 
Todo
ll_paul:在分布式系统中,调用组件最大的开销组件对象初始化时的开销,包括连接数
据库和建立对象,如果客户端是以全局变量的方式调用服务器端组件(例如在数据模块中使
用TDCOMConnection来连接服务器),那么一个客户程序进程只会导致服务器端激活一个组
件对象的实例,也就是说只会进行一次对象的初始化操作。如果客户端以局部变量的方式
,那么客户端每一次调用函数时,服务器端都要进行一次对象的初始化操作,例如:
procedure TForm1.Button1Click(Sender: TObject);
var
TempIntf : ISC_SimpleComObj;
s : WideString;
begin
TempIntf := CoSC_SimpleComObj.Create;
TempIntf.GetDateTime(s);
//GetDateTime的参数是Out,RetVal类型的
ShowMessage(s);
end;
以上代码是以局部变量的方式调用组件,这将导致每次按下Button1时,服务器端都要激活
一个对象的实例,如果用到数据库的话,要重新连接数据库,如果要读取配置文件的话,要
重新打开配置文件并读取之,这样一来,效率肯定要比用全局变量的方式低。但是,效率会
低很多吗?由于COM+有数据库连接池、对象池等技术,当一个客户端连接关闭时,服务器端
并不真正销毁对象及关闭数据库连接,从而使下一个客户端连接进来时,服务器端不用重复
连接数据库,这大大提高了系统的响应速度。实际情况是:当客户端数量较少时,你并不能
感觉到在客户端使用局部变量或全局变量调用服务器会有多少性能上的差异。
To wuisland:比如说客户端要提交一个新的请假单,我们可以在服务器端定义这样一个方法:
(我用了C/C++风格的代码)
int __fastcall AddLeaveRec(
BSTR EmployeeID, /* [in] 员工工号 */
DATE LvDate, /* [in] 请假日期 */
long Duration, /* [in] 请假天数 */
BSTR Reason, /* [in] 请假原因 */
int *Return /* [out,retval] 请假单处理结果 */
)
客户端在调用这个方法时,只把关键的信息传递给服务器,而不是把一句“Insert into ...”
语句提交给服务器端来执行,这样的好处是客户不用知道也不用操心该往数据库的哪个表、
哪个字段里插数据、数据类型是什么,不管服务端程序或是数据库结构发生了变化,只要
接口没有变,客户端程序都不用改。
 
收藏并登记。
 
to Sachow,首先,感谢您对这个主题的认真回复(包括我的问题),小弟非常感谢!
老兄说的连接池,在李维书上也写的很清楚上了,但我想知道,这个组件的连接池和二层
中的数据库连接池的效率能否做个比较?
我的意思是说:用组件连接池连数据库,和直接用ADO在客户端连的速度做个比较,谁比较
慢?
在此,我不想讨论是否应该用三层,和三层的好处,只是想进一步的说程序的运行的效率!
(同样,也不考虑程序更新时的麻烦,因为,这正是三层的一个最大好处!)
 
区别是会有的,但差别不会太大。如果要我说出差多少,我就没有办法了。这些连接池技术
并不是应用程序开发者自己做的,而是微软提供的,而且都是基于COM技术的,如果有些差
别的话,那是由于多层方式会有更多的对象之间调用的开销、Marshaling的开销,而且如果
应用服务器与数据库不在一台机器上的话,由于处理网络连接、传输造成的计算也必将使三
层慢于两层。
它们在性能上的差异主要来自于结构上的差异,两层结构对数据库的使用方式导致数据库的
负荷较大,从而降低系统的可扩展性,这就是为什么在客户端数量很大的情况下时两层结构
很难应付的原因。三层以更合理的方式利用资源,使得服务器在面对大客户量访问时仍能有
较好的性能,但如果考核到做每个简单任务时谁更快,那当然还是两层结构。
 
可以用这样的思想:
最初的应用是单机,数据和功能都放在一台机器上。随着应用向工作组模式发展中,人们迫切需要
调用彼此的数据,也调用彼此的功能,这样人们就不用重复录入数据,程序员也不须重复写
功能。数据和功能先共享哪一部分?虽然说通过功能就可以把数取出来,数据在功能屏蔽之下,似乎
无须共享出来,但是功能是基于数据的,功能共享出来了,单独放在一台机器上让大家使用,但是这个功能
需要的数据在A,B,C,D...上分布着,到底是谁?所以必须先共享数据。所以才有了C/S模式
一边是数据库,大家都对着这台机器访问数据,一边是大量的客户端,程序都在每台机器上。
随着部门间计算模式的发展,一个系统想存取另一个系统的数据,但是表结构已经很复杂了,
业务逻辑也已经错综复杂了,你已经不可能独自写一段程序存取另一个系统的数据。这时只能合作,
让对方写一个功能,给你开放出来,你一调用就能得到你想要的结果。但是这个功能写好是该放到哪台机器上吗?
肯定不可能放在每个客户端上,又需要单独放在一个机器上,于是C/S/S产生了
这是一个历史,你就明白了三层该放什么东西。
当然也顺便,就是另一些系统不调用的功能也放在了这个公共组件服务器上,来减少数据库连接
虽然有的文章上说这样可以减少更换程序的成本,这点倒不敢苟同,因为从实际开发中,如果客户端是GUI的,
你的很多改动会和GUI改变有关,你还得更新。如果你客户端是WEB,你还必须是三层,因为你客户端什么都没有
至于划分数据层,业务逻辑层只是为了引导你面向对象思考。说是为了更容易的修改,而不影响另一层,这个也是
比较困难,因为往往客户要求多显示一些东西或少显示一些东西,可以这样查,可以那样查,所以
往往数据层的SQL语句老变化,而且大多不能在原SQL上改,因为参数,字段或许都不一样,你改了,客户段的取数就很容易出错,
你也不敢保证它会在什么功能中被公用到,所以往往是又增加一个新SQL,和原SQL看起来90%一样,但又不完全一样。
客户端界面也老变,有时业务校验规则也不一样,业务处理方式也不一样,所以每层都需要改变
往往一个数据对象由两三张关系数据表组成,
在数据层表现为数据对象,但是由于业务处理的重点不一样,也为了速度考虑,取最必要的字段,
所以在这个数据对象中有各种各样的SQL,而不是一个SQL,但是每个SQL都是反映了这个数据对象的一个方面
然后写一些函数,专门针对这些数据对象做业务处理,还有一些函数专门负责数据校验,如不可为空,主键重复,类型出错等
在业务逻辑层分出两枝,一枝是业务逻辑规则校验,在其中也调用着数据层的数据校验规则,
另一枝是业务处理,就是调用数据层的各个函数来组合完成一件事,形成一个流程
总结一下,SQL一般都写在数据层,这是很自然的,业务逻辑层就是组合功能。不管数据层的函数
还是业务逻辑层的数据都和业务相关,对于数据层与业务无关的说法,在实际中行不通,因为在模型上
说,我们写在数据层上的那些接口方法应该是单独又分出一层,叫真正的业务逻辑层,而我这里写的业务
逻辑层,模型中叫Facade,就是为了简化客户端调用而做的外壳。但个人认为,模型中单分出一层意义不大,
因为每层都需要修改,少一层就好修改一些。而且纯粹的面向对象系统在世界上也从来没有存在过,如果
存在,那必定是一个理论家的东西,而不能实用,就象在实际中我们在设计关系型数据库时先三范式,后为了简化
编程和提供速度而反三范式。
客户端也不是多个功能放一个PAS文件中。因为客户往往要求功能组合。如A要和B功能放在一个界面,
B和C要拆开,所以客户端也是界面和数据操作和数据显示分开,为了在界面上看到的是多个功能在一起
但实际中却各不混杂,这是个功能模块划分,不是层次划分。如果从界面观点来看,是层次问题,因为界面和功能算两个层次
不要拘泥于理论,也不要放弃理论埋头编程,而是互相借鉴前进,目的就是两个,为了业务处理需要,
为了我们好维护程序。
再看看我开头讲的历史,你会发现,历史就是为了这两个目的而变化
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
D
回复
0
查看
2K
DelphiTeacher的专栏
D
后退
顶部