您的位置:首页 > 其它

设计模式:模板模式

2013-05-09 12:20 211 查看
模板模式

一、引子

这是一个很简单的模式,却被非常广泛的使用。之所以简单是因为在这个模式中仅仅使

用到了继承关系。

继承关系由于自身的缺陷,被专家们扣上了“罪恶”的帽子。“使用委派关系代替继承关

系”,“尽量使用接口实现而不是抽象类继承”等等专家警告,让我们这些菜鸟对继承“另眼相

看”。

其实,继承还是有很多自身的优点所在。只是被大家滥用的似乎缺点更加明显了。合理

的利用继承关系,还是能对你的系统设计起到很好的作用的。而模板方法模式就是其中的一

个使用范例。

二、定义与结构

模板方法(Template Method)模式:定义一个操作中的算法的骨架,而将一些步骤延

迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。这里

的算法的结构,可以理解为你根据需求设计出来的业务流程。特定的步骤就是指那些可能在

内容上存在变数的环节。

可以看出来,模板方法模式也是为了巧妙解决变化对系统带来的影响而设计的。使用模

板方法使系统扩展性增强,最小化了变化对系统的影响。这一点,在下面的举例中可以很明

显的看出来。

来看下这个简单模式的结构吧:

1) 抽象类(Abstract Class):定义了一到多个的抽象方法,以供具体的子类来实现它们;

而且还要实现一个模板方法,来定义一个算法的骨架。该模板方法不仅调用前面的抽象

方法,也可以调用其他的操作,只要能完成自身的使命。

2) 具体类(Concrete Class):实现父类中的抽象方法以完成算法中与特定子类相关的步骤。

下面是模板方法模式的结构图。直接把《设计模式》上的图拿过来用下:

三、举例

还是在我刚刚分析完源码的JUnit 中找个例子吧。JUnit 中的TestCase 以及它的子类就

是一个模板方法模式的例子。在TestCase 这个抽象类中将整个测试的流程设置好了,比如

先执行Setup 方法初始化测试前提,在运行测试方法,然后再TearDown 来取消测试设置。

但是你将在Setup、TearDown 里面作些什么呢?鬼才知道呢!!因此,而这些步骤的具体实

现都延迟到子类中去,也就是你实现的测试类中。

来看下相关的源代码吧。

这是TestCase 中,执行测试的模板方法。你可以看到,里面正像前面定义中所说的那

样,它制定了“算法”的框架——先执行setUp 方法来做下初始化,然后执行测试方法,最

后执行tearDown 释放你得到的资源。

public void runBare() throws Throwable {

setUp();

try {

runTest();

}

finally {

tearDown();

}

}

这就是上面使用的两个方法。与定义中不同的是,这两个方法并没有被实现为抽象方法,

而是两个空的无为方法(被称为钩子方法)。这是因为在测试中,我们并不是必须要让测试

程序使用这两个方法来初始化和释放资源的。如果是抽象方法,则子类们必须给它一个实现,

不管用到用不到。这显然是不合理的。使用钩子方法,则你在需要的时候,可以在子类中重

写这些方法。

protected void setUp() throws Exception {

}

protected void tearDown() throws Exception {

}

四、适用情况

根据上面对定义的分析,以及例子的说明,可以看出模板方法适用于以下情况:

1) 一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。

2) 各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。其实这可

以说是一种好的编码习惯了。

3) 控制子类扩展。模板方法只在特定点调用操作,这样就只允许在这些点进行扩展。比如

上面runBare ()方法就只在runTest 前面适用setUp 方法。如果你不愿子类来修改你

的模板方法定义的框架,你可以采用两种方式来做:一是在API 中不体现出你的模板方

法;或者将你的模板方法置为final 就可以了。

可以看出,使用模板方法模式可以将代码的公共行为提取出来,达到复用的目的。而且,

在模板方法模式中,是由父类的模板方法来控制子类中的具体实现。这样你在实现子类的时

候,根本不需要对业务流程有太多的了解。

下载:
http://download.csdn.net/detail/undoner/5335717
深入浅出设计模式-中文版

1、模板方法模式包括哪些角色以及角色的作用?

答:模板方法模式包括两种角色:抽象模板和具体模板。

抽象模板(Abstract Template)角色:

抽象模板是一个抽象类。抽象模板定义了若干个方法以表示一个算法的各个步骤,这些方法中有抽象方法也有非抽象方法,其中的抽象方法称作原语操作。重要的一点是,抽象模板中还定义了一个称作模板方法的方法,该方法不仅包含有抽象模板中表示算法步骤的方法调用,而且也可以包含有定义在抽象模板中的其他对象的方法调用,即模板方法定义了算法的骨架。

具体模版(Concrete Template)角色:

具体模板是抽象模板的子类,实现抽象模板中的原语操作。

2、模板方法的优缺点。

答:优点:可以通过在抽象模板定义模板方法给出成熟的算法步骤,同时又不限制步骤的细节,具体模板实现算法细节不会改变整个算法的骨架。在抽象模板模式中,可以通过钩子方法对某些步骤进行挂钩,具体模板通过钩子可以选择算法骨架中的某些步骤。在子类定义详细的处理算法时不会改变算法的结构,实现了代码的复用,通过对子类的扩展可以增加新的行为,符合“开闭原则”。

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

3、适合模板方法模式的情景有哪些?

答:设计者需要给出一个算法的固定步骤,并将某些步骤的具体实现留给子类来实现;

需要对代码进行重构,将各个子类公共行为提取出来集中到一个共同的父类中以避免代码重复。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: