模板方法

一、概述

在面向对象开发过程中,通常我们会遇到这样的一个问题:我们知道一个算法所需的关键步骤,并确定了这些步骤的执行顺序。但是某些步骤的具体实现是未知的,或者说某些步骤的实现与具体的环境相关。
例子1:银行业务办理流程
在银行办理业务时,一般都包含几个基本固定步骤:
取号排队->办理具体业务->对银行工作人员进行评分。
取号、排队和对银行工作人员进行评分业务逻辑是一样的。但是办理具体业务是个不相同的,具体业务可能取款、存款或者转账。

二、问题

如何保证架构逻辑的正常执行,而不被子类破坏 ?

三、解决方案

模板方法:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。 模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。(Template Method Pattern:Definethe skeleton of an algorithm in an operation,deferring some steps tosubclasses.Template Methodletssubclasses redefine certain steps of an algorithmwithoutchanging the algorithm’s structure. )

1) 模板方法模式是基于继承的代码复用基本技术,模板方法模式的结构和用法也是面向对象设计的核心之一。在模板方法模式中,可以将相同的代码放在父类中,而将不同的方法实现放在不同的子类中。
2) 在模板方法模式中,我们需要准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来让子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现,这就是模板方法模式的用意。模板方法模式体现了面向对象的诸多重要思想,是一种使用频率较高的模式。

四、适用场景

1) 一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。
2)各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。首先识别现有代码中的不同之处,并且将不同之处分离为新的操作。最后,用一个调用这些新的操作的模板方法来替换这些不同的代码。
3)控制子类扩展。模板方法只在特定点调用“ hook”操作 ,这样就只允许在这些点进行扩展。

五、类图

tool-manager

六、模式的组成

抽象类(AbstractClass): 定义抽象的原语操作(primitive operation) ,具体的子类将重定义它们以实现一个算法, 实现一个模板方法,定义一个算法的骨架。该模板方法不仅调用原语操作,也调用定义

具体子类 (ConcreteClass): 实现原语操作以完成算法中与特定子类相关的步骤。

七、效果

模板方法模式的优点:

1) 模板方法模式在一个类中形式化地定义算法,而由它的子类实现细节的处理。
2) 模板方法是一种代码复用的基本技术。它们在类库中尤为重要,它们提取了类库中的公共行为。
3) 模板方法模式导致一种反向的控制结构,这种结构有时被称为“好莱坞法则” ,即“别找我们,,我们找你”通过一个父类调用其子类的操作(而不是相反的子类调用父类),通过对子类的扩展增加新的行为,符合“开闭原则”

模板方法模式的缺点:

每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象,但是更加符合“单一职责原则”,使得类的内聚性得以提高。

八、实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//超类(父类)
function SuperClass(msg) {
this._msg = msg;
}
//hook method
SuperClass.prototype.beforedogreet = function() {
// body...
};
SuperClass.prototype.doGreet = function() {
this.beforedogreet();
var m = this.makeGreetMsg();
console.log(m);
};
SuperClass.prototype.makeGreetMsg = function() {
return 'super : ' + this._msg;
};
//子类(也叫派生类)
function ChildClass(msg) {

}
goog.inherits(ChildClass, SuperClass);
//@override
ChildClass.prototype.makeGreetMsg = function(msg) {
//在父类方法已有逻辑上进行扩展。省去重新写一遍了
var msg = ChildClass.superClass_.makeGreetMsg.call(this, msg);
return 'altered by childclass ' + msg;
};
//子类通过父类的构子(hook)方法,进行自定义 扩展
ChildClass.prototype.beforedogreet = function() {
console.log('before do greet')
};

//继承的实现方法
var goog = {};
goog.inherits = function(childCtor, parentCtor) {
/** @constructor */
function tempCtor() {};
tempCtor.prototype = parentCtor.prototype;
childCtor.superClass_ = parentCtor.prototype;
childCtor.prototype = new tempCtor();
/** @override */
childCtor.prototype.constructor = childCtor;
};

九、与其他相关模式

1)策略模式:模板方法使用继承来改变算法的一部分。 Strategy使用委托来改变整个算法。模板方法模式与策略模式的作用十分类似,有时可以用策略模式替代模板方法模式。模板方法模式通过继承来实现代码复用,而策略模式使用委托,把不确定的行为集中到一个接口中,并在主类委托这个接口。委托比继承具有更大的灵活性。
原文: http://blog.csdn.net/hguisu/article/details/7564039
一个不错的ppt http://pan.baidu.com/s/1eQ5sfkQ