零雨其蒙's Blog

做优秀的程序员
随笔 - 59, 文章 - 13, 评论 - 58, 引用 - 0
数据加载中……

零雨其蒙《UML和模式应用》学习笔记(十一)


(零雨其蒙原创 转载请注明)
2007
年 3 月 14 日星期三

第 37 章 使用模式设计持久性框架

持久性对象

                Persistent Object 是指需要持久性存储的对象。

框架

好莱坞原则

即“不要给我们打电话,我们会打给你”。意思是,用户定义的类(例如新的子类)将从预定义的框架类接收消息。这通常是通过实现超类的抽象方法来实现的。

 

   这种方式就是说框架(容器)来调用用户自定义的类,而不是相反,其实就是 Rod Johnson 所谓的“ IoC ”,而被 Martin Fowler 进一步解释的“依赖注入”( DI )。

 

线程安全

    作为技术服务子系统,持久性服务(其他的很多服务也一样)应该被设计成线程安全的。

关键思想

映射( mapping )

     在类和持久性存储(例如,数据库中的表)之间,对象属性和记录的域(列 ,字段)之间必须有某种映射关系。也就是说,在这种模式之间必须有模式映射( schema mapping ) 。

 

模式映射在 Hibernate 和 iBatis 等现代框架中都是包含在 XML 文档中的,在 Java 中对象由 POJO 来担当, Larman 已经说得足够详细。

 

对象标识( object identity )

      为了方便将记录与对象联系起来,确保没有不适当的重复,记录和对象必须有唯一的对象标识。

 

  数据库中会有完全相同的两条记录吗?按理来说应该没有吧(正常情况应该没有,也可能某个表没有设关键字?)

 

数据库映射器( database mapper )

          负责具体化和虚化的纯虚构数据库映射器。

              

具体化和虚化( materialization and dematerialization )

          具体化是指将持久存储中数据的非对象表示(例如记录)转换为对象。虚化是指与具体化相反的动作,也称为钝化( passivation )。

 

缓存( cache )

持久性服务为提高性能缓存具体化后的对象。

 

对象的事务状态( transaction operation )

         就对象与当前事务而言,了解对象状态是有用的。例如,了解哪些对象已经被修改以便决定是否需要将它们存入持久存储中。

 

事务操作( transaction operation )

提交和回滚操作。

 

滞后具体化( lazy materialization )

并非一开始就具体化所有对象,只有当需要时才具体化特定实例。

 

虚代理( virtual proxy )

    滞后具体化可以通过使用 ( 称为虚代理的 ) 智能引用( smart reference )来实现。

 

模式

将对象表示为表

     将对象表示为表( Representing Objects as Tables )模式 [BW96] 建议为每个持久对象类在关系数据库中定义一个表。包括基础数据类型( number , string , boolean 等)在内的对象属性将映射为列。

 

如果是这样,或许就要改变传统的从设计数据库开始设计系统了,数据库中的表是通过持久性对象来确定的。

 

 

对象标识符

     对象标识符( Object Identifier )模式 [BW96] 建议给每个记录和对象(或对象的代理)分配一个对象标识符( OID )

 

动机 : 为了确保记录的重复具体化不会导致重复对象,需要有关联对象和记录的一致性方法。

 

 

数据库映射器模式

          数据库代理( Database Broker ) [BW95] 模式,即创建一个类来负责对象的具体化、虚化和缓存。该模式也被称为数据库映射器( Database Mapper )模式 [Fowler01] 。

 

 

Template Method 模板方法( GoF )

该模式的思想是,在超类中定义一个方法(模板方法),超类定义了算法的框架,其中既有固定部分也有变化部分( 就是那些可以被子类重写的部分)。模板方法调用其它一些方法,这些方法中有些可能会被子类覆写。因此,子类可以覆写(重写 override )这些变化的方法,以此在变化点增加自己特有的行为。

 

 

           具体实现还会引入回调函数,钩子函数这样的技术,等有空我会就 C++ , Delphi , Java 和 C# 来分析一下这个主题。

 

 

缓存管理模式

  缓存管理( Cache Management )模式 [BW96] 建议由数据库映射器负责维护缓存。如果每个持久性对象使用不同的映射器,那么每个映射器就可以维护自己的缓存。

 

 

事务状态

              当执行删除或保存操作时,都是先将持久性对象转换成适当的状态(就是由数据库中将对象提出将其状态设为 Old Clean ),然后执行提交或回滚方法时,再真正修改数据库。这和 DBMS 做的事务管理原理差不多,中间做一个过渡,就好比要把一个文件从 C 盘转移到 D 盘,使用剪切,将文件保存在内存中(文件的状态改变了,位置从硬盘变成了内存),然后当在 D 盘执行粘贴命令时,才会真正将文件转移过来。这里面的内存就相当于 Old Clean 状态。

 

 

State 状态模式( GoF )

问题: 对象的行为依赖于它的状态,而它的方法中包含能够反映依赖状态的条件动作的 case 逻辑。是否存在替代条件逻辑的方法?

解决方案 :给每个状态创建状态类,并实现一个公共的接口。将语境对象中的依赖于状态的操作委派给其当前的状态对象。确保语境对象总是向反映其当前状态的状态对象。

 

听上去有些拗口,但时间上没那么复杂,其实还是使用的接口和多态(好多 GoF 模式用的都是这种方法),给持久性对象增加一个状态属性(类型是接口),然后与状态对象接口形成对应关系,存在不同的状态类来实现这一接口,根据持久性对象地状态属性被赋值为哪个具体的状态类,来决定调用哪个状态类的方法(多态)。详细情况看第 461 页的图就可以了。

P461 在性能方面,这些状态对象实际上是无状态的(没有属性)。因此,这些类只需要有一个实例(每个类都是单实例类)。例如,数以千计的持久性对象可以引用同一个 OldDirtyState 实例。

 

 

Command 命令模式( GoF )

问题: 如何处理需要诸如排序(优先级)、排队、延迟、记录日志或重做等功能的请求或任务?

解决方案 :为每个任务创建一个类,并实现共同的接口(这句话一出,往往就意味着使用多态)。

 

P462 动作成为了对象,因此可以被排序、记录日志、排队等。

 

 

虚代理

Virtual Proxy 是其他对象( real subject )的代理,当它第一次被引用时具体化该对象。

 

 

在 Java 中,可以使用动态代理实现虚代理。(需要再好好看看 Java 的动态代理)

 

 

 

第 38 章 UML 部署图和构件图

部署图

    部署图表示的是,如何将具体软件制品(例如可执行文件)分配到计算节点(具有处理服务的某种事物)上。部署图表示了软件元素在物理架构上的部署。

 

构件图

  构件

Component 表示封装了其内容的系统模块,它在其环境中的表现形式可以被替代。构件通过所提供的和所需要的接口定义了其行为。同样,如果构件作为类型,那么它的一致性是通过这些所提供的和需要的接口来定义的。 [OMG03b]

 

 

 

 

第 39 章 架构的文档化: UML 和 N+1 视图模型

软件架构文档 SAD

SAD 描述有关架构的总体想法,包含架构分析的关键决策。

从本质上讲, SAD 是对架构性决策(例如技术备忘录)的总结以及对 N+1 架构视图的描述。

 

 

N+1 (或 4+1 )视图模型

              4+1 视图模型 4 个视图分别是:逻辑、进程、部署和数据。“ +1 ”视图指的是用例视图。

 

架构视图的细节

逻辑视图

进程视图

部署视图

数据视图

安全视图

实现视图

开发视图

用例视图

 

准则

   不要忘记动机! 也就是要把为什么这样设计写清楚!

 

Struts 框架用到的模式

ActionServlet 是访问表现层的外观。

ActionServlet 和 Action 对象的设计采用了命令处理器模式。 ActionServlet 扮演了命令处理器角色,接收请求并将它们映射为 Action ( Action 是 Command 对象 )对象, Action 对象负责执行请求。  

ActionServlet 是前端控制器,处理请求的初始接触点。 Action 对象是业务委派——向“业务”或领域层服务委派的抽象。

Action 对象也扮演了适配器的角色,将框架调用适配为领域层对象的接口。

    ActionServlet 实现了模板方法模式, process 是模板, processXXX 是钩子方法。

 

 

第 40 章 迭代式开发和敏捷项目管理的进一步讨论

 

迭代开发各阶段的目标

    P487 UP 是用例驱动的 ,这意味着工作是围绕用例的实现来组织的。也就是说,每次迭代都要实现若干个用例或者用例场景(如果用例太复杂不能在一次迭代中完成)。

 

 

第一次迭代 选择要选择重要用例的简单场景或理想路径场景(主成功场景)。

在细化阶段 需要处理与该用例相关的具有重要架构意义的不同需求,这要可以迫使团队接触到架构的各个方面:主要层、数据库、用户界面、主要子系统之间的接口等。这就有助于及早创建跨越系统众多部分的 “广泛但浅显” 的实现 ——这是细化阶段的常见目标。

 

 

 

 

本书心得: 终于把这部巨著看完了,不过第 1 章到第 9 章都没做笔记,只是在一篇总结中对用例、领域模型等内容做了总结和讨论,但是没有从大局观上来记述 UP 各个阶段需要怎样做,持续的时间和创建的制品,等读第二遍时,从宏观角度在记述一遍,总结一下。另外很多模式、原则都需要在实践中去进一步理解,因此这不是看一遍就 over 的书。另外这也是一本入门书,下一步我会阅读一些本书提到的重要文献,对各个问题进行深入的探究,并配合实践(以 J2EE 和 Delphi 为工具和案例研究)。

posted on 2007-03-20 15:00 零雨其蒙 阅读(631) 评论(0)  编辑  收藏 所属分类: 学习笔记