c#三层架构.docx
《c#三层架构.docx》由会员分享,可在线阅读,更多相关《c#三层架构.docx(34页珍藏版)》请在冰豆网上搜索。
c#三层架构
一.三层架构图
2006052029123456
三层架构图三层架构图三层架构图
二.系统各层次职责
1.UI(UserInterface)层的职责是数据的展现和采集,数据采集的结果通常以Entityobject提交给BL层处理。
2.ServiceInterface侧层用于将业务或数据资源发布为服务(如WebServices)。
2.BL(BusinessLogic)层的职责是按预定的业务逻辑处理UI层提交的请求。
(1)BusinessFunction子层负责基本业务功能的实现。
(2)BusinessFlow子层负责将BusinessFunction子层提供的多个基本业务功能组织成一个完整的业务流。
3.(Transaction只能在BusinessFlow子层开启。
)
3.ResourceAccess层的职责是提供全面的资源访问功能支持,并向上层屏蔽资源的来源。
(1)BEM(BusinessEntityManager)子层采用DataAccess子层和ServiceAccess子层来提供业务需要的基础数据/资源访问能力。
(2)DataAccess子层负责从数据库中存取资源,并向BEM子层屏蔽所有的SQL语句以及数据库类型差异。
DBAdapter子层负责屏蔽数据库类型的差异。
ORM子层负责提供对象-关系映射的功能。
Relation子层提供ORM无法完成的基于关系(Relation)的数据访问功能。
(3)ServiceAccess子层用于以SOA的方式从外部系统获取资源。
注:
ServiceEntrance用于简化对Service的访问,它相当于Service的代理,客户直接使用ServiceEntrance就可以访问系统发布的服务。
ServiceEntrance为特定的平台(如Java、.Net)提供强类型的接口,内部可能隐藏了复杂的参数类型转换。
(4)ConfigAccess子层用于从配置文件中获取配置object或将配置object保存倒配置文件。
4.Entity侧层跨越UI/BEM/ResourceManager层,在这些层之间传递数据。
Entity侧层中包含三类Entity,如下图所示:
三.Aspect
Aspect贯穿于系统各层,是系统的横切关注点。
通常采用AOP技术来对横切关注点进行建模和实现。
1.SecurtiyAspect:
用于对整个系统的Security提供支持。
2.ErrorHandlingAspect:
整个系统采用一致的错误/异常处理方式。
3.LogAspect:
用于系统异常、日志记录、业务操作记录等。
四.规则
1.系统各层次及层内部子层次之间都不得跨层调用。
2.Entityobject在各个层之间传递数据。
3.需要在UI层绑定到列表的数据采用基于关系的DataSet传递,除此之外,应该使用Entityobject传递数据。
4.对于每一个数据库表(Table)都有一个DBEntityclass与之对应,针对每一个Entityclass都会有一个BEMClass与之对应。
5.有些跨数据库或跨表的操作(如复杂的联合查询)也需要由相应的BEMClass来提供支持。
6.对于相对简单的系统,可以考虑将BusinessFunction子层和BusinessFlow子层合并为一个。
7.UI层和BL层禁止出现任何SQL语句。
//?
?
?
五.错误与异常
异常可以分为系统异常(如网络突然断开)和业务异常(如用户的输入值超出最大范围),业务异常必须被转化为业务执行的结果。
1.DataAccess层不得向上层隐藏任何异常(该层抛出的异常几乎都是系统异常)。
2.要明确区分业务执行的结果和系统异常。
比如验证用户的合法性,如果对应的用户ID不存在,不应该抛出异常,而是返回(或通过out参数)一个表示验证结果的枚举值,这属于业务执行的结果。
但是,如果在从数据库中提取用户信息时,数据库连接突然断开,则应该抛出系统异常。
3.在有些情况下,BL层应根据业务的需要捕获某些系统异常,并将其转化为业务执行的结果。
比如,某个业务要求试探指定的数据库是否可连接,这时BL就需要将数据库连接失败的系统异常转换为业务执行的结果。
4.UI层(包括Service层)除了从调用BL层的API获取的返回值来查看业务的执行结果外,
4.还需要截获所有的系统异常,并将其解释为友好的错误信息呈现给用户。
六.项目组织目结构
以BAS系统为例。
//制动辅助系统
1.主目录结构:
2.命名空间命名:
每个dll的根命名空间即是该dll的名字,如EAS.BL.dll的根命名空间就是EAS.BL。
每个根命名空间下面可以根据需求的分类而增加子命名空间,比如,EAS.BL的子空间EAS.BL.Order与EAS.BL.Permission分别处理不同的业务逻辑。
3.包含众多子项目的庞大项目的物理组织:
核心子项目Core的位置:
Core子项目中包含一些公共的基础设施,如错误处理、权限控制方面等。
七.发布服务与服务回调
以EAS系统为例。
1.同UI层的Page一样,服务也不允许抛出任何异常,而是应该以返回错误码(int型,1表示成功,其它值表示失败)的形式来表明服务调用出现了错误,如果方法有返回值,则返回值以out参数提供。
2.如果BAS系统提供了WebService(Remoting)服务,则BAS必须提供BAS.Entrance.dll。
BAS.Entrance.dll封装了与BAS服务交换信息的通信机制,客户系统只要通过BAS.Entrance.dll就可以非常简便地访问BAS提供的服务。
3.如果BAS需要通过WebService(Remoting)回调客户系统,则必须提供仅仅定义了接口的BAS.CallBack.dll,客户系统将引用该dll,实现其中的接口,并将其发布为服务,供BAS回调。
4.当WebService的参数或返回值需要是复杂类型――即架构图中的ServiceEntity,则ServiceEntity应该在对应的BAS.EntranceParaDef.dll或BAS.CallBackParaDef.dll中定义。
WebService定义的方法中的复杂类型应该使用Xml字符串代替(注意,Entrance和CallBack接口对应服务的方法的参数是强类型的),而Xml字符串和复杂类型对象之间的转换应当在BAS.Entrance.dll或BAS.CallBack.dll中实现。
用三层架构与设计模式思想部署企业级数据库业务系统开发
1.三层架构介绍
1.1关于架构
架构这个词从它的出现后,就有许许多多的程序员、架构师们激烈地讨论着它的发展,但是架构一词的出现,却是随着三层架构的出现才出现的。
当然,目前应用三层架构开发也正是业界最关注的主题。
那么这里我们来看看单层、双层、三层甚至多层架构到底是怎么一回事。
单层结构是80年代以来小型应用的结构,在那个结构化编程充斥的时代,还没有出现架构的概念,典型的是基于Dbase、Foxbase等小型数据库的应用。
双层结构的同义词可以理解为传统的客户/服务器结构,尽管目前占统治地位的结构,但是其封装移植等方面的缺陷,已使它步入暮年,典型是基于Oracle、Infomix等大型数据库的C/S应用。
三层结构是传统的客户/服务器结构的发展,代表了企业级应用的未来,典型的有Web下的应用。
多层结构和三层结构的含义是一样的,只是细节有所不同。
之所以会有双层、三层这些提法,是因为应用程序要解决三个层面的问题。
1.2三层架构概述
随着软件工程的不断进步和规范以及面向对象编程思想的应用,人们对封装、复用、扩展、移置等方面的要求,使得双层架构显然更加臃肿繁琐,三层程序架构体系应运而生,可以说,三层架构体系结构是面向对象思想发展中的必然产物。
当然三层架构对于目前来说早已经不是什么新鲜事物了,最早听到这个词应该是几年前使用java知道的吧,j2ee三层架构体系流行了这么多年,一直没有使用过,不过j2ee三层架构体系的提出,对软件系统的架构产生了巨大的影响,Microsoft、Boland这些公司自然不甘落后,例如Microsoft的.net平台,更有甚者,称.net之c#为java的儿子。
那么何谓三层架构?
所谓三层架构,是在客户/服务之间加入了一个"中间层",也叫组件层。
它与客户层、服务器层共同构成了三层体系。
这里所说的三层体系,不是指物理上的三层,不是简单地放置三台机器就是三层体系结构,也不仅仅有B/S应用才有三层体系结构,三层是指逻辑上的三层。
通过引入中间层,将复杂的商业逻辑从传统的双层结构(Client-Server)应用模型中分离出来,并提供了可伸缩、易于访问、易于管理的方法,可以将多种应用服务分别封装部署于应用服务器,同时增强了应用程序可用性、安全性、封装复用性、可扩展性和可移置性,使用户在管理上所花费的时间最小化,从而实现了便捷、高效、安全、稳定的企业级系统应用。
1.3分层描述三层架构
三层体系的应用程序将业务规则、数据访问、合法性校验等工作放到了中间层进行处理。
通常情况下,客户端不直接与数据库进行交互,而是中间层向外提供接口,通过COM/DCOM通讯或者Http等方式与中间层建立连接,再经由中间层与数据库进行交互。
当然数据通过中间层的中转无疑是降低了效率,但是它脱离于界面与数据库的完美封装,使得它的缺点显然不值得一提。
典型的三层结构分为表示(presentation)层,领域(domain)层,以及基础架构(infrastructure)层,而微软的DNA架构定义了三个层:
表示层(presentation),业务层(business),和数据存储层(dataaccess),当然J2ee也有它不同的分法不过都大同小异吧。
既然我用.net做的开发,这大三层我无需多说了,根据我的理解,我对此做了更详细的分层,界面外观层、界面规则层、业务接口层、业务逻辑层、实体层、数据访问层、数据存储层共七层,其具体的调用如图1所示:
图1
由图1可以看出,虽然我将系统的架构分为七层,实际上大的方面来说,它就是一个典型的三层架构设计思想。
单从这个图来看,数据的调用显得繁琐而抽象,也许这时候就会有人说,我只是想实现界面上与用户交互,然后根据用户的请求将数据读出/写入数据库就好了,为什么要做如此复杂的分层调用呢?
从这个问句中我们也只看到了界面和数据库,也就是说从用户的需求来说,就是这两层而已,但是这里我们首先要搞清楚的是三层架构它主要是为程序员为了实现部署、开发、维护企业级数据库系统而服务的。
如果我们在中间层实现了对表示层和数据库层的完全脱离,其部署、开发、维护系统的费用和时间至少降低到原来的一半,甚至更多。
1.4部署企业级数据库应用
对于一个企业级数据库应用系统上的三层架构我是这样部署的:
系统通过浏览器或应用程序客户端提供与用户的交互平台,并向服务器提交请求(界面外观层);用户提交请求后,界面规则层对用户的数据按照业务逻辑层要求的接口参数封装规则封装用户数据,然后调用业务接口层对外提供的相应命令接口(界面规则层),业务接口层通过对数据进行解析并分别送入不同的逻辑处理并向用户返回处理结果(业务接口层);对于数据和命令的不同,处理方式也不同,我们将不同的处理方式都归类,并将接口层传入的数据及命令流入对应处理流程(业务规则层);这时,不同的处理流程分析数据和命令产生出对应的一个实体,这个实体根据其本身的属性和方法以及上层传入的命令,将数据处理为数据访问层需要的接口参数,并向数据访问层提交访问数据库的请求,并向业务接口层返回访问结果(实体层);数据访问层会将数据转化为数据库可识别的语句(SQL),并访问数据库层,访问结果会返回给实体层(数据访问层);数据库层处理上层传入的SQL,读写数据库内置对象,并根据其内置对象本身的关系对数据做进一步校验和处理(数据库层)。
这里我所讲到的企业级数据库应用系统,不论它是基于B/S应用系统上的三层架构设计,还是基于C/S应用系统上的三层架构设计,基本上是一样的,所不同的只是两种方式常用的数据传输协议的不同,B/S应用系统设计一般数据传递是通过HTTP来完成的,C/S应用系统设计则更多的是基于TCP/IP协议来传送数据的,当然,随着企业级应用系统对安全性方面要求的要求越来越高,更多的防火墙架设于物理线路之间,C/S应用系统的设计也越来越多地趋向于HTTP,典型的方式如:
CLIENT?
ISAPI/CGI?
ServerDatabase;
CLIENT?
WebService?
ServerDatabase;
既然提到这两种方式,我简单地提一下它们两者的区别及应用,它们的不同主要是中间层向客户端提供服务的方式不同,一般情况下这两种方式都需要架设专门用于受理客户端请求的WebServer,很明显,它更进一步地体现了三层架构的安全性。
中间层基于ISAPI/CGI的方式可以说正在被WebService方式所取代,这也正是面向对象思想的进一步应用。
ISAPI/CGI向客户端提供的服务实际上是远程调用函数,数据一般由程序员自定义结构存储,并基于HTTP与WebServer交互,而WebService向客户端提供的服务是远程调用类,常常采用XML存储数据,并基于SOAP与WebServer交互。
两者的优劣势也很明显,前者较XML封装方式,数据量小,传输速度快,后者因为XML的臃肿速度上来说是它的劣势,不过它的安全性以及开发速度占有明显得优势。
如果认真看图1中对各层的描述,不难看出,里面提到了工厂以及构造器,它是来自于设计模式中的一种思想。
其中业务逻辑层的业务规则层、实体层就是运用设计模式的思想来实现的。
2.设计模式思想的应用
2.1设计模式思想概述
设计模式思想引入企业级数据库系统开发,与传统的开发模式可谓是一场革命.设计模式之于面向对象的设计与开发的作用就有如数据结构之于面向过程开发的作用一般,其重要性不言而喻。
当然学习设计模式的过程也是痛苦的,
对于GoF的23种设计模式要一一学懂它,无疑是非常痛苦的。
面向对象系统的设计与分析实际上就是追求的两点:
一是高内聚,一是低耦合。
这也是我们软件设计所要追求的,无论是OO设计中的封装、继承、多态,还是我们的设计模式的原则和实例,都是主要为了追求这两点。
有人说,我们的系统小,使用设计模式会束缚我们的实现,其实不然,就如K_Eckel在他所写的《设计模式精解》一书中提到的:
设计模式体现的是一种思想,而思想是指导行为的一切,理解和掌握了设计模式,并不是说记住GoF的23种设计模式的设计场景以及解决方案,而实际接受的是一种软件设计思想的熏陶和洗礼,等设计模式的思想真正融入到你的思想中后,你就会不自觉得去采用设计模式的思想去设计你的系统,这才是最重要的。
因此我并不想重复地去讲述这23种设计模式,更不会拘泥于其中的任何一种,我只是根据我的经验和对设计模式的思想的理解,来实现我的业务逻辑层的设计。
我们在面向对象的设计中常常会遇到一些问题,比如说为了提高程序的高内聚低耦合,我们通常会抽象出一些类的公共接口以形成抽象基类,这样我们可以为它派生很多个子类,通过申明一个抽象基类的但被实例化为指向派生类的对象,以达到多态的目的。
然而当业务复杂并产生了大量的派生类时,程序员就得记住每一个派生类的名字然后New出一个指向它的指针。
这就给编写程序和维护代码带来了很大的困难,这种情况下我们如果要求客户端传入一个名称,我们用一个switch根据传入的名称来New一个子类,这就实现了中间层的封装。
还有比如我的一个数据库系统中,有几百个表/视图等对象,要对它们进行访问,如果只用面向对象的思想去操作它们,我们需要把这些数据库对象都抽象为类,封装它们自己的属性和方法,这样的工作量无疑是非常巨大的。
于是我利用设计模式的思想动态地分类抽象它们,也就是说,在访问它们之前,才产生具有实体意义的类。
我们可以将几十个、几百个属性、方法类同的数据库表做成一个TemplateClass,这样的封装方式使得代码量减少到原来的几十甚至几百分之一,而且它最大的好处是脱离了数据库……等等在面向对象设计中出现的问题我们大都可以用设计模式的思想去解决它,就如我们在c程序中遇到一些比较麻烦的功能时,就会想到用数据结构中的一些算法去解决它一样。
2.2数据库应用中设计模式的抽象
说了这么多,我就举一个例子来说明如何在三层架构部署的企业级数据库应用系统中如何使用设计模式:
数据库系统中我们最关心的就是如何操作数据库中的那些对象,我们可以将数据库中的对象看作是用来生产某一种产品的模具,每一种类型的对象就是一种模具,比如表、视图、存储过程,我们可以将它们当作是三种模具,当然你可以根据业务及数据库化分的更细一点,比如单表模具,主从表模具,视图模具、存储过程模具、数据库函数模具等等,不够的你可以去继续扩展;假使我们现在有一个工厂,它有好多个车间,每个车间只能够使用一种模具来生产产品,我们可以分别给它们起名字叫表车间、视图车间、存储过程车间等。
当用户想要往USER表中插入一条记录的时候,我们可以说成是在工厂要在表车间使用表模具生产出一个叫做USER的产品,然后产品进行加工的过程。
那生产并加工这个产品过程到底是怎么样的呢?
这里我说明一下工厂、车间、模具、产品它们各自的功能以及在一个产品在产生和加工过程中所处的环节,事实上根据它们的名字也不难理解。
工厂:
它要存贮下所有的产品名和车间名以及产品名与车间的多对一关系,用户需要知道自己要生产的产品名字是什么,工厂根据产品名来判断送交给哪个车间去处理.
车间:
车间使用它拥有的模具来产生一个具体产品
模具:
模具产生一个产品对象
产品:
进行自加工(插入、删除、修改、查询等)
那么,现在我们来看看当用户通过界面层的交互,想对表USER插入一条记录的过程:
事实上用户并不知道它现在操作表叫做USER,而界面层上的对象则必须知道当前操作界面所对应数据库表的名字,有了这个已知条件,界面层调用业务接口层的提供的获取表信息函数接口【例如:
DataSetGetTabInfo(string_tabname);//得到当前表的信息】,接口产生一个工厂,工厂就判断这个USER属于哪个车间生产,将USER转交给表车间,表车间产生一个表模具对象,并生产出一个名叫USER的产品对象,产品对象调用自己的获取信息函数【例如:
DataSetGetTabInfo(string_tabname);//得到当前表的信息,并记录到产品对象属性中,实际上这个GetTabInfo过程调用了数据访问层提供的花取字段信息接口】,对本身做了一次加工,也就是说此时USER这个产品已经拥有了USER表的信息(字段、主键等),然后返回到业务接口层,业务接口层将这个具体的USER产品返回给界面层,界面层得到产品后,将数据填充到产品的属性(行和列)中,实际上就是增加一行给字段赋值的过程,然后再调用业务接口提供的插入数据接口【例如:
InsertData(DataSet_tabinfo);】,同样的,接口产生工厂,工厂找到车间,重新构造产品,产品对象对本身做插入操作,返回。
这就是一个完整的操作过程。
当我真正地了解了GoF的《设计模式:
可复用面向对象软件的基础》中的思想后,我突然发现真正如K_Eckel所说,经过了一场软件设计思想的洗礼,做系统设计时的思想发生了质的变化,封装、复用、多态、抽象……
3.三层架构与设计模式在Web应用系统中的应用
3.1用c#描述系统架构设计
3.1.1在.net中创建工程
1)首先打开MicrosoftVisualStdio.Net2003,新建一个C#项目Web应用程序,如图2所示:
图2
2)在新生成的解决方案中加入以下类库:
GlobalDataTypeLayer:
公用参数层
BusinessLayer:
业务逻辑层(可以将里面的四层全部分开,建成类库)
DataAccessLayer:
数据访问层,为了更好的扩展,我在代码表现形式上只将该层从业务逻辑层分离出来
界面规则层可直接置于项目中,因为它是界面外观层的基类,在一个命名空间中使用比较方便。
各层之间互相的引用联系是这样的,首先要将GlobalDataTypeLayer命名空间在其它各层全部引用,UserRoleLayer命名空间中再引用BusinessLayer,BusinessLayer再引用DataAccessLayer。
引用事例图如图3所示:
图3
3.1.2应用于系统层次结构调用过程以及类的代码实现
3.1.2.1界面表示层类图(如图4)
图4
图2展示的是用户界面表示层的类图结构,图中显示了共三个类,WebFormClass与PrintControlClass都属于界面外观层。
WebFormClass这不仅仅表示一个类,而表示一批类,因为一般情况下与用户交流的类的属性及操作都大同小异,我们可以从一个基类中派生,以便于编程和管理。
当然如果有一些类差别比较大,可以重新概造相应的基类,重新派生,界面层的扩展可以很灵活地通过增加基类来实现。
PrintControlClass:
打印控制类,主要以客户端脚本来实现,不与服务器进行数据交互,打印预览之前,打印数据应由WebForm类提交给PrintControl。
PageBaseClass这个类属于界面规则层,它是WebForm的基类,事实上界面外观与界面规则可以放在一个命名空间中,它可以是一个类,也可以是多个类,业务的复杂程度也决定了PageBaseClass的扩展,根据不同的需求可以构造相应的WebForm基类来满足业务需求。
实现基类部分代码见附录A.
3.1.2.2业务逻辑层类图(如图5)
图5
图5展示了复杂的业务逻辑层调用过程,其中主要展示的类有六个类,不包含派生的子类。
ParamDataClass公用参数类,这个类事实上并不属于三层架构中的任何层,我单独将其定义为公用参数层,它与三层架构中的任何一个类都息息相关,实现代码见附录A
InterfaceImplClass是业务逻辑层向界面表示层提供的接口类,数据由界面规则层封装传入,对外接口函数根据业务需求可以增加。
该类的所有函数实现基本都很类似,我这里列出数据库连接和一个SaveData的代码实例,见附录A
ClassBuilderFactoryClass工厂类,它的作用是根据接口类传入的数据找到对应的生产构造部件(ClassBuilder),这里很重要的是包含了一个简单的map,该结构在连接数据库里进行实例化,代码实现见附录A
ClassBuilderClass这是构造部件的抽象基类,其下可以根据业务的需求扩展很多的构件器,可以用工厂的模式理解其为构件车间,我这里派生的构件器有:
TableClassBuilder:
实体表构件器
ViewClassBuilder:
视图构件器
ProcedureClassBuilder:
存储过程构件器
OtherClassBuilder:
其它构件器
基类和实体表构件器的代码实现见附录A
EntityDataClass这是实体类的抽象基类,其下也可以根据业务的需求扩展派生实体,前面我提到过我们的构件器与实体类是一一对应的,一个构件车间只能够生产一类产品。
那么对应的派生实体就有:
TableEntityData:
表实体
ViewEntityData:
视图实体
ProcedureEntityData:
存储过程实体
OtherC