菜鸟笔记
提升您的技术认知

JAVA设计模式--模板方法模式

阅读 : 1850

一、什么是模板方法模式

模板方法(TemplateMethod)模式是一种对象的行为模式。定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

模版方法模式的本质:固定算法骨架  

二、模板方法模式的结构

模板方法模式涉及的角色及其职责如下:

抽象类(AbstractClass)角色:用来定义算法骨架(template method)和原语操作(primitive operation),具体的子类通过重定义这些原语操作来实现一个算法的各个步骤。在这个类里面,还可以提供算法中通用的实现(general operation)。
           具体实现类(ConcreteClass)角色:用来实现算法骨架中的某些步骤,完成与实现类自身相关的某些功能。

模板方法模式结构示意源代码如下:

先看看抽象类的写法,示例代码如下。

public abstract class AbstractClass {

	/**
	 * 模板方法
	 */
	public void templateMethod() {
		// 调用原语操作和通用操作
		generalOperation();
		primitiveOperationA();
		primitiveOperationB();

	}

	// 原语操作A,算法中的必要步骤,父类无法确定如何真正实现,需要子类来实现
	public abstract void primitiveOperationA();

	// 原语操作B,算法中的必要步骤,父类无法确定如何真正实现,需要子类来实现
	public abstract void primitiveOperationB();

	protected void generalOperation() {
		System.out.println("执行通用操作...");
	}
}

再来看看具体实现类写法,示例代码如下。

/**
 * 具体实现类,实现原语操作,并可以添加与自身功能相关的其他操作
 */
public class ConcreteClass extends AbstractClass {

	// 具体的实现
	@Override
	public void primitiveOperationA() {
		System.out.println("执行原语操作A...");
	}

	// 具体的实现
	@Override
	public void primitiveOperationB() {
		System.out.println("执行原语操作B...");
	}

}

接下来看看客户端的示例,示意代码如下。 

public class Client {

	public static void main(String[] args) {
		// 创建一个模板实例
		AbstractClass abstractClass = new ConcreteClass();

		// 执行实例的模板方法
		abstractClass.templateMethod();
	}
}

运行程序打印结果如下:  

执行通用操作...
执行原语操作A...
执行原语操作B...

三、模板方法模式相关知识点

抽象类和接口:

• 接口是一种特殊的抽象类,所有接口中的属性自动是常量,也就是public final static的,而所有接口中的方法必须是抽象的。
           • 抽象类,简单点说是用abstract修饰的类。这里要特别注意的是抽象类和抽象方法的关系,记住两句话:抽象类不一定包含抽象方法;有抽象方法的类一定是抽象类。
           • 抽象类和接口相比较,最大的特点就在于抽象类中是可以有具体的实现方法的,而接口中所有的方法都是没有具体的实现的。
           • 通常在“既要约束子类的行为,又要为子类提供公共功能”的时候使用抽象类。

变与不变:

• 程序设计的一个很重要的思考点就是“变与不变”,也就是分析程序中哪些功能是可变的,哪些功能是不变的,然后把不变的部分抽象出来,进行公共的实现,把变化的部分分离出去,用接口来封装隔离,或者是用抽象类来约束子类行为。
           • 模板方法模式很好地体现了这一点。模板类实现的就是不变的方法和算法的骨架,而需要变化的地方,都通过抽象方法,把具体实现延迟到子类中了,而且还通过父类的定义来约束了子类的行为,从而使系统能有更好的复用性和扩展性。

 好莱坞法则:

• 什么是好莱坞法则呢?简单点说,就是“不要找我们, 我们会联系你”。
           • 模板方法模式很好地体现了这一点。作为父类的模板会在需要的时候,调用子类相应的方法,也就是由父类来找子类,而不是让子类来找父类。
           • 这其实也是一种反向的控制结构。按照通常的思路,是子类找父类才对,也就是应该子类来调用父类的方法,因为父类根本就不知道子类,而子类是知道父类的,但是在模板方法模式里面,是父类来找子类,所以是一种反向的控制结构。

“后期绑定”技术:

• 在Java语言中,对于出现子类覆盖父类方法的情况,在编译时是看数据类型,运行时则看实际的对象类型(new谁就调用谁的方法)。
           • 在使用模板方法模式的时候,虽然用的数据类型是模板类型,但是在创建类实例的时候是创建的具体的子类的实例,在调用的时候,会被动态绑定到子类的方法上,从而实现反向控制。其实在写父类的时候,它调用的方法是父类自己的抽象方法,只是在运行的时候被动态绑定到了子类的方法上。 

四、模板方法模式的适用性

在面向对象系统的分析与设计过程中经常会遇到这样一种情况: 对于某一个业务逻辑(算法实现)在不同的对象中有不同的细节实现, 但是逻辑(算法)的框架(或通用的应用算法)是相同的。模板方法提供了这种情况的一个实现框架。

模版方法模式是采用继承的方式实现这一点: 将逻辑(算法)框架放在抽象基类中, 并定义好细节的接口,子类中实现细节。

策略模式解决的是和模板方法模式类似的问题, 但是策略模式是将逻辑(算法)封装到一个类中,并采取组合(委托)的方式解决这个问题。

模板方法应用于下列情况:
           • 固定定义算法骨架,实现一个算法的不变的部分,并把可变的行为留给子类来实现。
           • 各子类中具有公共行为,应被提取出来,集中到一个公共父类中去实现,以避免代码重复,即“重分解以一般化”。
           • 控制子类扩展。模板方法模式只在特定点调用子类的方法,这样就只允许在这些点进行扩展。  

五、模板方法模式的优缺点

使用模板方法模式的优点:

• 模板方法模式是一种实现代码复用的很好的手段。通过把子类的公共功能提炼和抽取,把公共部分放到模板中去实现。

使用模板方法模式的缺点:

• 模板方法模式最基本的功能就是通过模板的制定,把算法骨架完全固定下来。事实上模板和子类是非常耦合的,如果要对模板中的算法骨架进行变更,可能就会要求所有相关的子类进行相应的变化。所以抽象算法骨架的时候要特别小心,尽量确保是不会变化的部分才放到模板中。 

六、总结

模板方法模式主要是通过制定模板,把算法步骤固定下来,至于谁来实现,模板可以自己提供实现,也可以由子类去实现,还可以通过回调机制让其他类来实现。
           通过固定算法骨架来约束子类的行为,并在特定的扩展点来让子类进行功能扩展,从而让程序既有很好的复用性,又有较好的扩展性。