前文详细介绍了Façade模式、Adapter模式、Strategy模式和Bridge模式,并进行了比较。本文将再介绍四个常用的设计模式:Abstract Factory(抽象工厂)模式、Decorator(装饰)模式、Observer(观察者)模式、Template Method(模板)模式。开始介绍之前,笔者想说一下自己经常纠结的一个问题,什么时候开始考虑应用模式?作为一个新手,刚接触设计模式时都会为之倾倒,自觉醍醐灌顶,非常的迫切将所学的设计模式应用于实践,所以在编程的初期就会考虑各种模式的应用。个人的经验告诉我,对业务的理解是一个渐进明细的过程,开发的初期往往很难看到整个业务需求的全貌和本质,此时强行应用设计模式往往会导致Over Engineering。笔者认为应用设计模式的最佳时机往往是在代码重构的时候,彼时你已掌握业务的本质,对模式的应用往往能够恰到好处,其实这也是JIT的思想。
一.Abstract Factory模式
1. 目标:需要为特定的客户(或情况)提供对象组,组内之间的对象处于一个上下文环境。
2. 问题:需要实例化一组相关的对象,并从对象创建逻辑层面保证对象之间正确的关系,例如:在游戏设计中,在非洲大陆,不能够创建出美洲豹对象。
3. 解决方案:协调对象组的创建。提供一种方式,将如何执行对象实例化的规则从使用这些对象的客户对象中提取出来,实现对象创建和对象使用的解耦。
4. 参与者和协作者:Abstract Factory为如何创建对象组的每个成员定义公共接口。特定的ConcreteFactory创建其所对应的具体对象组。
5. 效果:抽象工厂模式将“使用那些对象”的规则与“如何使用这些对象”的逻辑进行解耦,实现关注点分离。
6. 实现:定义一个抽象类来指定创建哪些对象。然后为每个组实现一个具体类。代码请参考06. 设计模式应用案例(上)。UML图如下:
二.Decorator模式
1. 目的:在运行时,实现动态的为每一个对象添加职责。
2. 问题:要使用的对象将执行所需要的基本功能。但是,这些基本功能确定以后,可能需要为这个对象添加一些其他的附加功能,并且对于不同的情况可能添加的附加功能的种类和数量都是不确定的。
3. 解决方案:通过添加装饰类,而不是扩展子类,在运行时为基本类对象扩充功能。抽象的说:有一个基本功能,还有些可选功能,每一个具体的对象,在基本功能的基础上通过选用不同的可选功能来定制。基本功能作为:ConcreteComponent;可选功能作为:ConcreteDecorator。
4. 参与者和协作者:ConcreteComponent让Decorator对象为自己添加功能。有时候用ConcreteComponent的派生类提供核心功能,在这种情况下ConcreteComponent不再是具体的,而是抽象的。Component类定义了所有这些类的接口。
5. 效果:附加功能放在Decorator对象中。好处是可以在ConcreteComponent对象的功能之前或之后添加功能(取决于Decorator类的具体实现),但是对象链总是终于ConcreteComponent对象。
6. 实现:创建一个抽象类来表示原类和要添加到这个类的功能。在装饰类中,将对新功能的调用放在对紧随其后对象的调用之前或之后,以获得正确的顺序。调用方式为new ConcreteDecorator(new ConcreteComponent())。代码请参考07. 设计模式应用案例(下)。UML图如下:
三.Observer模式
1. 目标:解开观察者和主体之间的耦合,二者之间的关系在运行时动态建立,实现订阅--发布模型(Pub-Sub Model).
2. 问题:对象间经常存在这样一种关系:某个对象状态的改变将导致另一些对象的状态变化。或者说,有些对象作为观察者在始终盯着某个对象,一旦有事发生就需要立即行动。抽象的说:当主体发生变化时,不同的观察者做出不同的行动,而且他们的行动是自我控制的,无需主体发出指令。
3. 解决方案:通过将主体和观察者分开,而不是简单的将观察者的行为硬编码到主体类中,观察者通过监测主体类的实践实现自我控制。
4. 参与者和协作者:Subject由三个函数构成:Attach(添加新的观察者)、Detach(删除过时的观察者)、Notify(依次更新观测者的信息);Observer定时更新自己的状态,根据主体的变化,做出相应的反应。
5. 效果:观察者对主体而言是透明的,观察者可以自发的做出反应。
6. 实现:创建一个Subject类,包含有三个函数。还有一个ConcreteSubject类获得主体的状态信息。创建一个Observer的抽象基类,还有不同观测者的ConcreteObserver类,定时更新自己的信息。代码请参考07. 设计模式应用案例(下)。UML图如下:
四.Template Method模式
1. 目标:定义业务逻辑中算法的骨架,将一些步骤推迟到子类中实现。可以不改变算法的结构而重新实现这个算法中的某些步骤。
2. 问题:要完成在某一细节层次一致的一个过程或一系列步骤,但其中个别步骤在更细节的层次上有不同的实现。
3. 解决方案:允许定义可变的子步骤,同时保持基本步骤和步骤之间的执行顺序不变。
4. 参与者和协作者:Abstract Class,该类中有一个定义了一般算法的方法(Template Method)这个方法调用了代表算法中各步骤的方法(Primitive Operation)。Concrete Class,实现Primitive Operation以完成算法中与特定子类相关的步骤。
5. 效果:提供了一个很好的代码复用平台,并且从结构上减少了算法出错的概率。同时,提供了一种机制,使得约束、规则可以一次编码,处处使用。对于具体类的实现者而言,无需关注整个算法,只需关注该具体类中特殊的实现逻辑即可。
6. 实现:创建一个抽象类,用抽象方法实现一个过程。这些抽象方法必须在子类中实现,以执行过程的每个步骤。如果这些步骤是独立变化的,那么每个步骤都可以是Strategy模式来实现(很多情况下,模式都不是独立使用,而是组合使用)。代码请参考07. 设计模式应用案例(下)。UML图如下: