一个四层应用体系架构 [CBOFramework C# Beta 1 ]
小气的神
2002-5-12
Article Type: Overview
难度等级: 7/9
版本: 3.22
有关 dotNET 下的应用体系构架的话题,我们可以明确的从某一点开始,但是可能没有结束的那一点,永远没有 :) 一大批原来 COM+ 的程序员开始在 COM 和 dotNET 之间走钢丝,一方面忙于将重点和应用向 dotNET 构架上转移,一方面还要照顾着原来的 COM 。最后这些程序员将在经历了某一个学习曲线之后坦然的面对两者,掌握了如何分别和两者交互和周旋的技巧。但是问题可能才刚刚开始,因为他们很快开始问这样的问题:今后的程序该怎么写,程序的构架是怎样的?
太多的程序构架模型,让他们开始有些眼花缭乱了,新的概念和技术似乎太多了,掌握了这些概念之后会发现一种无从下手的感觉,你不知那一种方式是相对最好的。 Paul D. Sheriff (PDSA, Inc.) 在 4 月底的 MSDN 上发表了 ** Designing a .NET Application ** ( Updrading to Microsoft.NET ) 的文章,里面有总结了目前 dotNET 下常用的几种程序构架和各自的特点。事实上,当你使用 ADO.NET, ASP.NET, COM+, Web Services , XML, Remoting, DCOM/SOAP/HTTP 就可以象他那样组合出不下 20 种的三层或多层构架形式。另外还可以加上 MSMQ 和 SQLXML 。
一部分程序员已经开始有些怨言,相对于 J2EE 的严格规范, dotNET 下的架构似乎过分开放了。相信这种状态还会持续一段时间, Microsoft 也需要经历一个优化和整合的过程才能做出富有成效和建设性的指导和建议。这之前的时间里,对于应用架构的选择问题可能会落到 ISV 和开发人员身上。
经过一段时间的发展过程中,有一些原则已经被总结出来,并且被越来越多的应用起来,比如:
1. 使用统一和强健的 DAL ( Data Access Layout )和存储过程,使得数据服务层更加接口化和高效能。
2. 应用面向对象分析和设计将 Business 层组件和对象化,从而顺利使用设计模式,提高可重用性。
3. 设计时充分考虑面向 Web Services 的接口和功能。
4. 使用 dotNET 接口和属性将三层更加细化和分层以提供更高层次的抽象。
5. 层与层之间的接口越来越“松散耦合”,稳定性和灵活性明显获得提高。
6. 使用 COM+ 的比重开始降低, COM+ 被精确的应用分布式、多数据库和核心中间件上。
7. 商务逻辑更加细化,一定比重的商业逻辑的实现从商业逻辑层移到表现层,由多层共同完成。
8. Web Server 开始慢慢成为离客户端最近的业务逻辑代理和资源、权限的控制器。
9. WebForm 和 WinForm 提供了丰富的 UI ,使得表现层有更多精力处理用户会话、登录、权限等问题。
10. XML 和 Schema 被更多的应用在设计中,往往成为系统中多层之间联系和通讯的“胶水”和介质。
下面要说的这个四层应用体系架构源于《 Designing Solutions With COM+ Technologies 》中的 11 章的一个实例。 Wade Baron 将原来的三层结构进行了调整,其一是实现客户端的对象化访问,其二是将业务逻辑层分为事务服务层和对象服务层,对象服务位于表现层(客户端),事务服务在原来的业务逻辑层,位于服务器端。具体的见下图:
CBOFramework 框架体现了上面的 2,4,7 , 10 的一些特征,特别是引入了面向对象的设计和分析,结束了返回 ADO 记录集的 Business 对象的混乱表现,使得表现层有更多的精力处理自己的逻辑。另外一方面由于实现了抽象和对象化,使得设计时可以应用目前已知的多种设计模式。
CBOFramework 中也使用了 Collection 的技术和概念,但它不同于早先 Mike McClure (Microsoft) 和 Leo Romano(Sierra System Group Inc) 描述的 ** ECC(Engine-Collection-Class) Framework ** 。 CBO 也可以应用 Object Factory 或其他的设计模式,但作为核心设计上 CBO 没有强调设计模式,而是体现了接口编程和面向对象分析技术。在表现上 CBO 没有 ECC 那么直观和有针对性,我个人认为 CBO 更加强大和先进,负载上比 ECC 的 Collection 传递要小许多,并且由于是接口设计更容易扩展,比如可以使用 dotNET 新的 Remoting 、 SOAP 协议作为分布协议,当然两者并不冲突,理解 ECC 对于理解 CBO 有很大帮助,因为两者有些是相同的。
由于篇幅有限,我将不翻译原文的设计思路和描述, 强烈建议你从原著和书中获得更详细的设计思想和内部流程 。本文将提供原来没有的类图表示(这是从 Visual Studio.NET 中反向工程我的代码获得的)我将整个框架按 dotNET 的方式以 C# 重新编写(原来作者提供一个 Visual Basic 版本的 Project ),表现层,我没有使用作者的,而是重新写了一个简单的进行测试,(我更希望未来直接使用作者的例子,因为他的客户端实现更好和更完整)。另外, Shippers 对象(三个类)我没有完成,因为理解框架后一些对象的实现基本上是 Copy/Paste 的过程。例子使用的数据库是 SQL Server 和 MS Access 数据库中著名的 Northwind 的样本数据库,未进行删改。
系统需要的环境: Visual Studio.NET EN RTM+, SQL Server 2000 SP2.
细节和实现:
整个框架定义了四个接口、一个对象持久性的实现和一个 Object Collection 的实现。
接口: IPersistObjectStream 和 IObjectStream 是客户端接口
接口: IPersistTransStream 和 ITransStream 是服务器端接口。
CBOCollection 是一个 Object Collection 实现,被用于实现对象集合。
所有对于每个对象的集合比如 :Customers 、 Orders 等等都必须一个集合对象,由于 dotNET 不提供 generic porgramming 特性 (templates) ,那么为每一个现实对象实现一个 Type-safe 的集合对象将是痛苦的。这里我使用了 Chris Sells 提供的 CollectionGen 工具,产生了一个 Object 类型的通用 CBO Object Collection 。 ( 生产速度很快,而且很方便但不是 Type-Safe 的 Collection ,这意味着可能会有一定类型转换的性能消耗,太多集合对象,一个一个产生似乎太 ….)
CStream 实现 IObjectStream 和 ITransStream ,这个类实现了将客户端的对象保持到数据库中(对象持久性)。目前这个类借助 XML ,使得客户端将通过透露的接口把对象序列化到这个 XML 流中,并且可以进行读取;同时服务器端事务对象可以从这个对象透露的接口中读取数据。
事务服务层( Transaction Services )的对象
所有的事务层对象都必须实现 IPersistTransStream, 这个接口被流对象调用,用来将数据写到数据库中。下面是一个 Customers 事务对象的实现
对象服务层( Object Services )的对象
对象服务层的对象:对象和对象集合都必须实现 IPersisObjectStream 接口。这个接口主要由流对象使用,用来从 XML 流中加载对象和将对象状态保存到 XML 数据流中。
客户端:
使用 CBOFramework 的好处可以在客户端得到最好的体现,现在表现层用户可以将自己的精力完全放在表现层的界面和业务逻辑流程的处理上,而不用理会记录集字段的次序和类型转换。表现层的用户可以更加容易的使用这些和现实中类似的对象来进行编程和操作,达到和业务流程的对应。
|
典型的 DNA 架构
|
CBOFramework
---|---|---
获得对象
|
Dim RetRst as AD.ORecordset
Dim Customer as Object
Set Customer = CreateObject(“Custom”)
set RetRst =
Customer. GetByCustomerID( txtSearch.Text )
|
CCustomers m_oCustomers = null ;
CCustomer m_oCustomer = null
m_oCustomers = new CCustomers() ;
m_oCustomer =
m_oCustomers.GetByCustomerID( txtSearch.Text )
绑定
|
txtCompany.Text = RetRst(“Company”)
txtContact.Text = RetRst(“Contact”)
txtTitle.Text = RetRst(“Title”)
txtAddress.Text = RetRst(“Address”)
txtCity.Text = RetRst(“City”)
|
txtCompany.Text=m_oCustomer.Company;
txtContact.Text= m_oCustomer.Contact ;
txtTitle.Text = m_oCustomer.Title ;
txtAddress.Text = m_oCustomer.Address ;
txtCity.Text = m_oCustomer.City ;
修改
|
lret = Customer.UpdateAddress( Addre)
|
m_oCustomer.Address = Addre ;
m_oCustomer.Save() ;
删除
|
lret = Customer.DeleteCustomer ( CuID)
|
m_oCustomer.Delete() ;
新增
|
lret = Customer.AddNew ( A1,A2,A3…)
|
m_oCustomer = new CCustomer() ;
m_oCustomer.Campany = A1 ;
m_oCustomer.Contact = A2 ;
………
m_oCustomer..Save() ;
当然这里简化了一些,典型 DNA 架构下的一些记录集的检索、计算、求和等等被简化了,事实上这些逻辑经常乱七八糟的排在表现层的代码中。 CBOFramework 最终达到我们的目的:提高可重用性,代码更加简洁和易于维护。
未来:
这是 CBOFramework 的第一个版本,其目标是理解其架构并将其在 dotNET 平台上实现。必须承认这个版本是非常原始和简陋的,仍有许多没有完成。它仅仅阐明了整个框架,展示了对这个框架的一个实现和应用,我想未来会对 CBOFramework 做更多的补充和调整,比如下一个版本会增加下面一些特性:
1. 目前还不能算是真正的分布式,所有的事务服务层对象还没有从 ServicedComponent 继承(我注释了这可能不是最终方案),那么对象服务层和事务服务层的通讯(非本机)还必须通过 DCOM ,也就是需要在 COM+ 进行打包部署。下一个版本会实现在对象服务层和事务服务层实现 Remoting 协议通讯,当然最好同时兼容 DCOM 。
2. 实现一个通用的 DAL 或 DAO (Data Access Object) ,统一事务服务层对于数据库的访问方式,使之兼容 MSSQL , XML 、 OLEDB 和 SQLXML 。
3. 完善应用的实例,并且通过使用一个创建类型的设计模式,使原来的作者的 VB 实例( COM 用户)可以透明的使用新的组件。另外增加 ASP.NET 的实例。
4. 将框架中使用的 XML 函数进行整理,统一成一个 XMLHelp 类便于重用。
5. 基于上述 CBOCollection 的描述,将这个类的实现从 CBOFramework 的命名空间中移出来,放到次一级的命名空间,便于以后使用的框架的用户决定实现自己的 Object Collection 类。
总结:
以上我们基本讨论一个和原来 Windows DNA 相关的体系结构的