零雨其蒙's Blog

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

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

(零雨其蒙原创 转载请注明)
2007
3 10 日星期六

得墨忒耳定律

    该定律(更通俗的名字叫“不要和陌生人说话”)的含义是,不要历经远距离的对象结构路径去向远距离的间接对象 ( 陌生人 ) 发送消息(说话)。该定律约束了你应该在方法里给哪些对象发送消息,其要求在方法里,只应该给以下对象发送消息:

1)          this 对象(自身)

2)          方法的参数

3)          this 的属性

4)          作为 this 属性的集合中的元素

5)          在方法中创建的对象

Information Hiding 信息隐藏

              Parnas 所指的信息隐藏绝非数据封装的思想,而是由于困难和可能的变化对其他模块 隐藏 与设计相关的 信息 。以下引用了他对信息隐藏的论述,并作为指导性的原则:

      实际上,我们所建议的是,以一组困难的设计决策可能变化的设计决策作为开始。然后,设计每个模块,使其对其他模块隐藏此类决策

 

           我的理解: 也就是说,我们要对于依赖它的模块隐藏那些容易变化的部分(信息),很显然,我们经常遇到触一发而动全身的情况,而且有时这种情况还很频繁的出现,这意味着在设计时我们向外界暴露了容易变化的部分(信息,消息等),因此慎重的考虑公开的部分( public 方法或属性),是 OOD 的难点。

 

 

OCP 开放—封闭原则

          P315 OCP 的定义是:模块应该同时(对扩展、可适应性)开放和(对影响客户的更改)封闭。

 

 

 

 

26 应用 GoF 设计模式

GRASP 原则对其他设计模式的归纳

  适配器模式 支持防止变异( PV ,因为它通过应用了接口和多态的间接转换对象,改变了外部接口或第三方软件包。

   我觉得这幅图非常好的反映了模式之间的关系,了解模式的动机有助于理解模式,这是我从自己学习模式和其他技术时得到的最好的经验之一。该图使用了泛化—特化的分类学表示法,有助于了解 GoF 设计模式的本质,其实对于 GRASP 模式而言,弄清各个模式的关系(主次、大小、推导)也是很有意义的。(该图位于 319 页)

    在学习完这一章后我将把 GoF 设计模式按照 GRASP 重新分类,那或许是明天要做的事情了,而且或许随着实践的延伸,这种分类将变得越来越有意义。

Adapter 适配器

问题: 如何解决不相容的接口问题,或如何为具有不同接口的类似构件提供稳定的接口?

解决方案: 通过中介适配器对象,将构件的原有接口转换为其他接口。

 

这个方案我暂时理解为,添加一个对象,这个对象含有一种方法,这种方法能将一个接口 IA 转换为另一个接口 IB (就可以说 IA 通过适配器转换,使其可以通过 IB 访问其他对象),比如将 ICommonAccounting (通用财务系统接口)转换为 ISAPAccounting SAP 财务系统接口),两个接口不同就可能比如都有一个叫获得总帐信息的方法,在通用财务系统中只需要有一个参数,而在 SAP 财务系统中需要有多个参数,这样就造成了接口不统一。就好比日本的电压是 110V 而中国是 220V ,就需要一个变压器(变压器的别名其实就是适配器),这样就可以在中国使用日本的电器了。在变压器内部,将 220V 转成了 110V

适配器模式简单理解就是,增加一个中间层,使其可以访问一个原来对象不能访问直接的对象(原因是接口不匹配)。所谓转换也不是变魔术,其实就是通过适配器来访问某个对象,将其结果返回给调用适配器的那个对象。(应该就是如此简单的完成了接口的转化,暂时我是这样理解的)

Factory 工厂

问题: 当有特殊情况(例如存在负责的创建罗辑、为了改良内聚而奋力创建职责等)时,应该由谁来负责创建对象?

解决方案 :创建成为工厂的纯虚构对象来处理这些创建职责。

 

   无论怎么说,我们必须指定要创建的类,因为这不是变魔术,可以采用反射机制(在 Java 中),动态的指定类名( String 型的,可以从外部特性文件或 XML 文件中读取),然后根据指定类名来生产要的类。(这样做可以避免使用条件分支语句, if 需要 A 类,生产 A 类等等)。但是如果所使用的语言不支持反射机制(例如 Delphi )呢?我先前都是用条件分支语句搞定的,等看完 Delphi 模式编程那本书可能就会明白了。

 

 

Singleton 单实例类

问题: 只有唯一实例的类即为“单实例类”。对象需要全局可见性和单点访问。

解决方案 :对类定义静态方法用以返回单实例。

 

下面来一段代码来说明 Singleton ,并且解决多线程应用中的并发问题。

public static synchronized [U1]   ServicesFatory getInstance()

{

   if(instance==null)

     {

         Instance=new ServicesFatory();

}

return instance;

}

 

这里多线程解决方案是缓式初始化(lazy initialization)。整个代码来看非常朴素,如果instance已经存在就直接返回,否则创建一个新的。instance是一个static实例,即静态属性。

 

上述三种设计模式的关系

    基本上也是基于动机来理解的,为了解决接口不匹配的问题(就是一个对象不能直接访问对象的方法,而需要一个中间层),而创建了适配器,而对于不同的外部系统需要不同的适配器,因此需要一个工厂来生产相应的适配器,然而适配器可能需要常常生产,而工厂不必总是被创建(当然,每天都要生产计算机,但是没有必要每天都把生产计算机的工厂都重盖一遍),于是我们创建了只有一个实例的工厂类,也就是单实例类

   通过大一统的思想来理解,三种模式的一般用法就可以了然于心了(不过 Larman 已经在本章的开头提醒我们本书对于设计模式的讲解只是初级的,面对复杂的现实问题,可能并没有这样易于理解)。

 

Strategy 策略

问题: 如何设计变化但相关的算法或政策?如何设计才能使这些算法或政策具有可变更的能力。

解决方案 :在单独的类中分别定义每种算法 / 政策 / 策略,并且使其具有共同的接口。

 

注意:语境对象需要其策略的属性可见性(就是说策略要作为语境对象的属性)。

 

实际上,策略是多态的一个应用,策略也是基于多态技术的,其含义在解决方案中已经可以完全读出了。

 

 

Composite 组合

问题: 如何能够像处理非组合(原子对象)一样,(多态地)处理一组对象或具有组合结构的对象呢?

解决方案 :定义组合和原子对象的类,使它们实现相同的接口。

 

组合对象的标志性特性 外部的组合对象包含一组内部对象,外部和内部对象实现相同的接口。

 

从书中给的 Java 实现代码可以看出,组合对象实现了和其内部对象相同的接口,而其内部对象又是以集合的形式(定义为它们共同的接口)作为组合对象的属性,然后组合对象通过一个 add 方法,来动态装载原子对象,使其成为其内部对象,这样就将那些有共同接口的原子对象组合到一起了。组合对象和原子对象(都实现了同一个接口)都可以由工厂来生产。

    组合也是基于多态的。

将聚合对象作为参数传递

         惯例: 避免将子对象从父对象或聚合对象提取出来,并且传递这些子对象。相反,应该传递包含子对象的聚合对象。(不要单独把聚合对象的子对象一个一个拎出来,然后传递它们,要传的话就直接传聚合对象就好了。)

 

 

Facade 外观

问题: 对一组完全不同的实现接口(例如子系统中的实现和接口)需要公共、统一的接口。可能会与子系统内部的大量事物产生耦合,或者子系统的实现可能会改变。怎么办?

解决方案 :对子系统定义唯一的接触点——使用外观对象封装子系统、该外观对象提供了唯一和统一的接口,并负责与子系统构件进行协作。

 

外观将一个子系统隐藏于其后 ,就像键盘一样,键盘隐藏了计算机,计算机来处理我们的请求(击键),但是我们完全不知道计算机的方法,我们只知道同时按 Ctrl+Alt+Del 可以调出任务管理器,这就是外观(键盘)的一个公开的方法(按那三个键子)。

 

适配器对象可能用来封装对具有不同接口的外部系统的访问。这就是一种外观,但是其强调的是对不同接口的适配,因此被更具体的称为适配器( P337 )。 如果这样说的话,那么适配器就是外观模式的特化了

 

Observer 观察者 / 发布—订阅 / 委派事件模型

问题: 不同类型的订阅者对象关注与发布者对象的状态变化或事件,并且想要在发布者产生事件时以自己独特的方式作为反应。此外,发布者想要保持与订阅者的低耦合。如何对此进行设计呢?

解决方案 :定义“订阅者”或“监听器”的接口。订阅者实现此接口。发布者可以动态注册关注某件事情的订阅者,并在事情发生时通知它们。

 

 

通过本书所给示例可以看到,发布者内部有一个装载订阅者(监听器、观察者)的集合(这意味着所有订阅者实现同一个接口),并且有一个将订阅者加入到该集合的方法,同时有一个通知集合中每一个订阅者的方法被称为发布“特性事件”)。然后订阅者负责去改变其他对象的状态。

 

 

我的总结 组合模式和观察者模式都用到了集合,组合模式是将子对象放入组合对象中的集合属性中,而观察者模式是将观察者放入发布者对象的集合属性中。然后都是通过遍历来调用或通知集合中的每一个对象。

 

观察者模式也是基于 多态 的。

 

P409 当初与较低层的应用或领域层需要向上与 UI 层通信时,通常使用观察者模式。


  [U1] 使用该关键字来支持多线程

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


只有注册用户登录后才能发表评论。


网站导航: