当前位置:编程学习 > C#/ASP.NET >>

实战揭秘:开发.Net平台应用系统框架

答案:     作者:孙亚民 本文选自:赛迪网
  微软的.Net平台给应用程序开发提供了一个非常好的基础系统平台,但是,如何在这个系统平台上构建自己的应用系统,还需要我们针对应用系统的特点,构建自己的应用系统框架(Framework)。我们在应用.Net开发系统的过程中,结合多年的开发经验,也参考了J2EE的架构,设计了一套.Net下的应用系统框架,以及相应的中间件和开发工具,已经在多个项目中和软件产品中应用,取得了很好的效果。现在向代价介绍这个框架的整体解决方案,希望对您有所帮助。
  
  我们知道,对于典型的三层应用系统来说,通常可以把系统分成以下三个层次:
  
  · 数据库层
  
  · 用户界面层
  
  · 应用服务层
  
  对于应用系统来说,在这三个层次中,系统的主要功能和业务逻辑在应用服务层进行处理,对于系统框架来说,主要处理的也是这个层次的架构。
  
  对于应用服务层来说,在一个面向对象的系统中,以下几个方面的问题是必须要处理的:
  
  · 数据的表示方式,也就是实体类的表示方式,以及同数据库的对应关系,即所谓的O-R Map的问题。
  
  · 数据的存取方式,也就是实体类的持久化问题,通常采用数据库来永久存储数据实体,这就需要解决同数据库的交互问题。这个部分要完成的功能,就是将数据实体保存到数据库中,或者从数据库中读取数据实体。同这个部分相关的,就是对数据访问对象的使用。在框架中,我们对ADO.Net又做了一层封装,使其使用更加简便,同时也统一了对ADO.Net的使用方式。
  
  · 业务逻辑的组织方式。在面向对象的系统中,业务逻辑是通过对象间的消息传递来实现的。在这个部分,为了保证逻辑处理的正确性和可靠性,还必须支持事务处理的能力。
  
  · 业务服务的提供方式。为了保证系统的灵活性和封装性,系统必须有一个层来封装这些业务逻辑,向客户端提供服务,同时作为系统各个模块间功能调用的接口,保证系统的高内聚和低耦合性。这里的客户指的不是操作的用户,而是调用的界面、其他程序等。Web层(ASP.Net页面)通常只同这个部分交互,而不是直接调用业务逻辑层或者数据实体的功能。
  
  为了能够很好的解决这些问题,我们设计了这个框架。在框架中,针对以上问题,我们将应用服务层又划分成五个层次:数据实体层、实体控制层、数据访问层、业务规则层和业务外观层。各个层次同上述问题的关系可以用表表示如下:
  
  
  层次 问题
  数据实体层 数据的表示方式
  实体控制层 数据的存取方式
  数据访问层 提供对数据库的访问,封装ADO.Net
  业务规则层 业务逻辑的组织方式
  业务外观层 业务服务的提供方式
  
  
  
  整个系统的结构图如下:
  
  
  
  图中的箭头表示使用关系
  
  将系统划分成这么多层次,其好处是能够使得系统的架构更加清晰,这样每个层次完成的功能就比较单一,功能的代码有规律可循,也就意味着我们可以开发一些工具来生成这些代码,从而减少代码编写的工作量,使得开发人员可以将更多的精力放到业务逻辑的处理上。正是基于这个想法,我们同时开发了针对这个框架的开发工具,并在实际工作中减少很多代码的编写量,效果非常好。同时,为了应用服务层更好的工作,我们设计了一个支持这个框架的应用系统中间件。(现在,已经有多家其他公司在试用这个中间件系统。)
  
  同J2EE的EntityBean不同的是,我们采用了数据实体和实体控制分开的设计方法,这样的做法会带来一定的好处。
  
  下面我将各个部分的设计方案和策略详细介绍如下:
  
  数据实体层
  
  我们首先需要解决的是数据的表示方式的问题,也就是通常的O-R Map的问题。
  
  O-R Map通常的做法是将程序中的类映射到数据库的一个或多个表,例如一个简单的Product类:
  
  
  public class Product
  {
  string ProductID;
  string ProductName;
  float Account;
  }
  
  
  
  
  在数据库中可能对应了一张Product表:
  
  
  字段名 数据类型
  ProductID Varchar(40)
  ProductName Varchar(50)
  Account float
  
  
  
  这是最通常的做法,但是,由这种方式会带来一些问题。首先就是数据实体在数据库和程序中的表现方式不一样,对于一些涉及到多个表的“粗粒度对象”,一个实体类可能会引用到多个其它实体类,也就是说会在涉及到对象粒度的建模方面带来一些问题;其次在同数据库交互时,也涉及到一个转换的问题,如果一个对象涉及到对多个表的操作,问题就更大;最后,当系统做查询操作,需要返回多个对象时,因为涉及到转换的问题,效率就比较低下,而如果采用直接返回数据集的方式,虽然能够提高效率,又会带来数据表达方式不一致的问题。
  
  考虑到上述问题,我们在数据实体的表现上采用了另外一种方式,那就是利用DataSet。DataSet是微软在ADO.Net中新提出的数据对象,同ADO的Recordset不同的是,他能够容纳多个记录集。DataSet类似于一个内存数据库,由多个DataTable组成,而一个DataTable又有多个Column。这样的结构,使得他可以同数据库很好的进行映射。同时,我们吸取了J2EE架构中CMP使用XML文件定义实体类结构的优点,采用了类似的解决方案。
  
  因此,在这个方面我们是这样来进行处理的:
  
  1) 核心类库定义了EntityData类,这个类继承了DataSet,添加了一些方法,用来作为所有实体类的框架类,定义了各个实体类的一般结构,至于每个实体类具体的结构,在运行时刻由下述办法确定:
  
  2) 实体类的定义通过XML文件来确定,该XML文件符合JIXML对象实体描述语言的规范(注:JIXML是我们开发的 对象-实体 映射语言),用于确定实体类的结构。例如,一个关于订单的实体类的定义可能类似于下面的结构:
  
  3) 实体对象的结构由一系列的类构造器在运行时刻,根据上述规范制定的XML来生成。这些类构造器实现IClassBuilder接口。我们在系统核心类库中预定义了一些标准的Builder,一般情况下,直接使用这些标准的Builder就可以了。
  
  类构造器采用的类构造工厂的设计模式,如果使用者觉得标准的Builder不能满足要求,也可以扩展IClassBuilder接口,编写自己的类构造器,然后在系统配置文件中指明某各类的类构造器的名称即可。
  
  IClassBuilder的定义如下:
  
  
  public interface IClassBuilder
  {
  EntityData BuildClass(string strClassName);//获取类数据结构
  SqlStruct GetSqlStruct(string strClassName,string strSqlName);
  }
  
  
  
  
  这个部分的结构可以用类图表示如下:
  
  
  当使用者需要某个实体类的时候,只要采用如下语句:
  
  
  EntityData entity=EntityDataManager.GetEmptyEntity("Product");
  
  
  
  
  EntityDataManager的GetEmptyEntity方法通过调用ClassBuilder的BuildClass来实现,并且实现对象的缓存功能。
  
  ClassBuilder的BuildClass方法实现如下:
  
  
  public EntityData BuildClass(string strClassName)
  {
  IClassBuilder
  builder=ClassBuilderFactory.GetClassBuilder(strClassName);
  return builder.BuildClass(strClassName);
  }
  
  
  
  
  这儿综合使用了Builder和Factory的设计模式。ClassBuilderFactory的作用是根据实体类的名称,读取配置文件中相应的类构造器的具体类名,并返回具体的类构造器。
  
  配置文件ClassBuilders.xml的结构很简单:
  
  
  <?xml version="1.0" encoding="gb2312" ?>
  <Builders>
  <Class Name="ProductType"
  BuilderName="Jobsinfo.SingleTableClassBuilder" />
  </Builders>
  
  
  

上一个:单元测试和事先测试开发(2)
下一个:ASP.NET Web 服务还是 .NET Remoting:如何选择(1)

CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,