深入解析Java的设计模式编程中的模板方法模式
定义:
定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定步骤。
听起来好高端的样子,我的理解:
1.父类声明了若干个抽象方法(基本方法)和若干个具体方法(模板方法)
2.抽象方法是一个算法(过程)的步骤,在子类中实现
3.模板方法是一个算法(过程)的框架,在父类中已经约定好,实现对基本方法调用,完成固定的逻辑
4.一个算法(过程)的结构在父类中定义,具体的实现细节则在子类中实现
注:为了防止恶意操作,一般模板方法都加上final,禁止重写
通用类图:
事实上,模版方法是编程中一个经常用到的模式。先来看一个例子,某日,程序员A拿到一个任务:给定一个整数数组,把数组中的数由小到大排序,然后把排序之后的结果打印出来。经过分析之后,这个任务大体上可分为两部分,排序和打印,打印功能好实现,排序就有点麻烦了。但是A有办法,先把打印功能完成,排序功能另找人做。
abstract class AbstractSort { /** * 将数组array由小到大排序 * @param array */ protected abstract void sort(int[] array); public void showSortResult(int[] array){ this.sort(array); System.out.print("排序结果:"); for (int i = 0; i < array.length; i++){ System.out.printf("%3s", array[i]); } } }
写完后,A找到刚毕业入职不久的同事B说:有个任务,主要逻辑我已经写好了,你把剩下的逻辑实现一下吧。于是把AbstractSort类给B,让B写实现。B拿过来一看,太简单了,10分钟搞定,代码如下:
class ConcreteSort extends AbstractSort { @Override protected void sort(int[] array){ for(int i=0; i<array.length-1; i++){ selectSort(array, i); } } private void selectSort(int[] array, int index) { int MinValue = 32767; // 最小值变量 int indexMin = 0; // 最小值索引变量 int Temp; // 暂存变量 for (int i = index; i < array.length; i++) { if (array[i] < MinValue){ // 找到最小值 MinValue = array[i]; // 储存最小值 indexMin = i; } } Temp = array[index]; // 交换两数值 array[index] = array[indexMin]; array[indexMin] = Temp; } }
写好后交给A,A拿来一运行:
public class Client { public static int[] a = { 10, 32, 1, 9, 5, 7, 12, 0, 4, 3 }; // 预设数据数组 public static void main(String[] args){ AbstractSort s = new ConcreteSort(); s.showSortResult(a); } }
运行结果:
排序结果: 0 1 3 4 5 7 9 10 12 32
模版方法模式的结构
模版方法模式由一个抽象类和一个(或一组)实现类通过继承结构组成,抽象类中的方法分为三种:
抽象方法:父类中只声明但不加以实现,而是定义好规范,然后由它的子类去实现。
模版方法:由抽象类声明并加以实现。一般来说,模版方法调用抽象方法来完成主要的逻辑功能,并且,模版方法大多会定义为final类型,指明主要的逻辑功能在子类中不能被重写。
钩子方法:由抽象类声明并加以实现。但是子类可以去扩展,子类可以通过扩展钩子方法来影响模版方法的逻辑。
抽象类的任务是搭建逻辑的框架,通常由经验丰富的人员编写,因为抽象类的好坏直接决定了程序是否稳定性。
实现类用来实现细节。抽象类中的模版方法正是通过实现类扩展的方法来完成业务逻辑。只要实现类中的扩展方法通过了单元测试,在模版方法正确的前提下,整体功能一般不会出现大的错误。
模板方法模式的优点:
1. 封装不变部分,扩展可变部分
2. 提取公共部分代码,便于维护
3. 行为由父类控制,子类实现
模板方法模式的适用场景:
1. 多个子类有公共方法,并且逻辑基本相同
2. 对复杂的算法,核心算法设计为模板方法,细节功能则由各个子类实现
3. 重构代码
模板方法模式的扩展
- 基本方法由于不需要对外提供访问,因此可以设计为protected类型
- 设计钩子方法(Hook Method):对外部提供接口,可以影响模板方法内的具体执行顺序
总结:
父类建立框架,子类在重写了父类部分方法后,再调用从父类继承的方法,产生不同的结果。