俺的回收站

架构分析 解释编译原理
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

设计架构优秀的 Framework - 兼谈 ORM Framework

Posted on 2007-01-14 10:34  Riceball LEE  阅读(18846)  评论(10编辑  收藏  举报
本文只是自己在实际架构Framework积累的微薄的经验,如有谬误请大侠专家不吝赐教为盼。
架构设计是一种权衡和取舍。一个Framework是为了解决某一个领域内的某些问题的代码复用而因运而生的,而问题总是有多种的解决方案的。而我们要确定唯一的架构设计的解决方案,就意味着我们要在不同的矛盾体之间做出一个取舍。我们在设计的过程总是可以看到很多的矛盾体:开放和整合,一致性和特殊化等等。任何一对矛盾体都源于我们对Framework的不同期望,需要我们在各种方案中作出不同的取舍。没有一个Framework能够满足所有的要求,只是架构的侧重不同。而一个设计优秀的 Framework 则是体现在其架构简单明了,层次分明,重用价值高;运行高效率,稳定(完善的TDD测试机制)。

一个架构优秀的 Framework,至少要满足以下的特征:
    * 重用:为了避免重复劳动,为了降低成本,我们希望能够重用之前的代码、之前的设计。重用是 Framework 实现中最为核心的目标,重心中的重心。提高复用度是Framework的首要目标。
      * 层次分明,高度部件(组件)化: 在框架中的各个部件高度独立,可拆可组(任意拆卸,任意组合),着力通用。
      * 部件细化,设计精巧,运行高效,内存占用低。
      * 耦合度低(可拆可组)
    * 高效:不论是什么系统,我们都希望架构是高效的。
    * 安全:运行安全稳定【可以通过完善TDD测试机制来保障】
    * 延展:我们需要架构具有可拓展性,以适应未来可能的变化。
    * 简明:一个复杂的架构不论是测试还是维护都是困难的。我们希望架构能够在满足目的的情况下尽可能的简单明了。【但是简单明了的含义究竟是什么好像并没有一个明确的定义。例如:使用模式能够使设计变得简单,但这是建立在我熟悉设计模式的基础上。对于一个并不懂设计模式的人,他会认为这个架构很复杂。】
    * 透明:把过多的实现细节隐藏起来,仅把需求的接口呈现出来(具体的实现对使用Framework的开发者来说就是透明的)。这样就提高了使用者的效率,降低了学习的门槛。

设计具体指导原则:
  1、概要框架总体功能目的
  2、对框架总体功能目的进行细化,分层(层次之间相对独立,互不干涉),仔细斟酌,理清层次之间的依赖关系(如,核心层,中间层,应用层)。
     * 核心层:处于最低层,不依赖于Framework中的其它层;
     * 中间层:根据具体 Framework 的需要自行定义,取名,注意理清层次之间的依赖关系;
     * 应用层:在核心层以上,依赖于核心层;
  3、从核心层开始,逐层细化各个部件,仔细推敲部件名称,构思部件的功能,合理归类。

ok,现在让我们看看 ORM Framework 的是为了解决什么问题而出现的呢?
面向对象建模和编程经过这么多年的发展已经相当成熟,其优势在于能够适应软件开发过程中的不断变化的需求。在面向对象编程的时候很显然我们建立的对象是放在计算机内存之中,如果关闭计算机那么我们的对象就不存在了,对象的永久性(也就是长久保存对象)是我们一直的期望。在O/R Mapping出现前我们设计程序不得不花费大量的精力和时间构建我们的Data Access Layer (DAL数据存取层),如果项目规模比较大的时候可想而知这个DAL层的复杂程度,涉及到异构数据库那就更加复杂。

在我看来,ORM Framework 的出现是为了解决两个问题:
  1. 数据库无关性:平滑迁移数据库和异构数据库;
  2. 实体对象的持久性:关系数据库的数据与对象的对应关系。

从这里就可以初步看出,架构至少有两个层次:
  1. 数据库存取层Database Access Layer作为核心层,实现数据库无关性;
  2. 实体对象映射层 ObjectMapping Layer 作为应用层实现数据到实体对象的映射,该层依赖于核心层。

数据库存取核心层是独立通用处于最底层的实现,可以直接拿出来使用的,必须保持高效和安全,主要的功能如下:
  * 规范数据库操作,构造 Database 工厂模式(可拓展性),形成数据库操作包裹类 【微软的 Data Access Application Block 】
  * 规范 SQL 语句,解决不同的数据库之间的 SQL 语句的差异【最简单的方式方式就是在程序中以SQL语句Id的形式调用SQL语句,将SQL语句集中于一个文件。iBatis 的 DataMapper 采用类似机制,不过它采用的是XML格式,格式的冗余数据降低了加载的效率,在保存加载机制上不够灵活,至少该让用户选择保存为不同的格式;iBatis DataMapper 另一个问题就是将 ObjectMapping 也包含其中,层次不分明,降低可复用性,】。

实体对象映射层考虑的问题就多了:
 * 简单实体对象属性的映射
 * Collection对象属性的映射,如实体对象购物车的物品清单就是一个Collection对象属性,收录了该购物车中的所有的物品。
 * 实体对象 MetaData 的考虑,
 * 业务规则,约束的考虑等等。。。

这里我就映射这个问题随便说两句,实体对象映射层是效率最低的一个层次,原因在于映射操作:将实体对象变为数据库数据,数据库数据变为实体对象,而正是这个映射操作使得运行速度大大降低,内存占用大大的增加。
如果将所有的实体数据不分青红皂白全部对象化,那么即使是采用Cache(是以牺牲内存为代价的)和分页机制(一次不要取个万把千条数据的,客户也看不过来,一次百来条数据就差不多了,这样就减少了内存的占用和映射操作的时间),但是,当系统面临逐渐增加的并发访问数量面前,系统的性能恶化相当厉害。我不知道大家说的什么才算是大型系统,企业级应用,也许是特指那些愿意花高价购买IBM RS/6000之流的机器的冤大头们吧。但是对于我们这些搞技术的,则是该将注意力集中在如何充分挖掘机器的每一分潜力上才是,我相信对于每一个量入为出的企业来说,它应该是欣赏的。
这个目前,我也没有想到什么好的办法,对于减少内存开销,有个建议就是在设计时候,尽可能的延迟加载时间(如实体对象购物车的物品清单,实际数据的加载只有当访问该属性的时候才加载,而对于大的备注,Blob类型的属性也可以采取类似的机制)。实际上,大多数用户的操作都是在浏览,因此对于浏览数据的形式,可以绕过ObjectMapping层,通过数据库存取层返回dataset直接操作,这样也能进一步提高速度和降低内存的消耗。

有时间以后再说...