《模板方法模式》
(本文是内容来源网络其它作者分享博文,结合自身的理解,仅作为知识记录)
简介:定义一个算法中的操作框架,而将一些步骤延迟到子类中。使得子类可以不改变算法的结构即可重定义该算法的某些特定步骤。
类型:行为类模式
类图:
举个栗子:
程序员A拿到一个任务:给定一个整数数组,把数组中的数由小到大排序,然后把排序之后的结果打印出来。
经过分析之后,这个任务大体上可分为两部分:排序和打印,打印功能好实现,排序就有点麻烦了。但是A有办法,先把打印功能完成,排序功能另找人做。
首先定义一个抽象排序的类AbstractSort,程序员A定义了一个sort()抽象函数表示排序,打算找其它人完成此功能点。
第二步自己完成 shouSortResult (int[] array) 函数,把sort() 排序好并且显示出来
1 abstract class AbstractSort { 2 3 /** 4 * 将数组array由小到大排序 5 * @param array 6 */ 7 protected abstract void sort(int[] array); 8 9 public final void showSortResult(int[] array){ 10 this.sort(array); 11 System.out.print("排序结果:"); 12 for (int i = 0; i < array.length; i++){ 13 System.out.printf("%3s", array[i]); 14 } 15 } 16 }
A找到程序员B,让他帮忙实现sort()抽象函数排序的功能
程序员B一看,定义了一个ConcreteSort 类继承抽象类 AbstractSort,
1 class ConcreteSort extends AbstractSort { 2 3 @Override 4 protected void sort(int[] array){ 5 for(int i=0; i<array.length-1; i++){ 6 selectSort(array, i); 7 } 8 } 9 10 private void selectSort(int[] array, int index) { 11 int MinValue = 32767; // 最小值变量 12 int indexMin = 0; // 最小值索引变量 13 int Temp; // 暂存变量 14 for (int i = index; i < array.length; i++) { 15 if (array[i] < MinValue){ // 找到最小值 16 MinValue = array[i]; // 储存最小值 17 indexMin = i; 18 } 19 } 20 Temp = array[index]; // 交换两数值 21 array[index] = array[indexMin]; 22 array[indexMin] = Temp; 23 } 24 }
程序员B写好后A拿过来进行测试:
直接用抽象类对象new 排序类 ConcreteSort(),并调用自己写好的 showSortResult() 函数。
1 public static int[] a = { 10, 32, 1, 9, 5, 7, 12, 0, 4, 3 }; // 预设数据数组 2 public static void main(String[] args){ 3 AbstractSort s = new ConcreteSort(); 4 s.showSortResult(a); 5 }
运行结果:
排序结果: 0 1 3 4 5 7 9 10 12 32
答:
- 模板方法:可以有一个或几个,一般是一个具体方法,sort() 就是模板方法,也就是一个框架,实现对基本方法的调用,完成固定的逻辑。(抽象模板中的基本方法尽量设计为protected类型,符合迪米特法则,不需要暴露的属性或方法尽量不要设置为protected类型。实现类若非必要,尽量不要扩大父类中的访问权限)。
- 基本方法:是由子类实现的方法,并且在模板方法被调用,文中showSortResult(一般都加上final关键字,防止被覆写)。
- 模板方法模式是通过父类建立框架,子类在重写了父类部分方法之后,在调用从父类继承的方法,产生不同的效果,通过修改子类,影响父类行为的结果,模板方法在一些开源框架中应用非常多,它提供了一个抽象类,然后开源框架写了一堆子类,如果需要扩展功能,可以继承此抽象类,然后覆写protected基本方法,然后在调用一个类似TemplateMethod()的模板方法,完成扩展开发。
优点:
- 封装不变部分,扩展可变部分。把认为不变部分的算法封装到父类中实现,而可变部分的则可以通过继承来继续扩展。
- 提取公共部分代码,便于维护。
- 行为由父类控制,子类实现。
缺点:
- 按照设计习惯,抽象类负责声明最抽象、最一般的事物属性和方法,实现类负责完成具体的事务属性和方法,但是模板方式正好相反,子类执行的结果影响了父类的结果,会增加代码阅读的难度。
- 编程界的一条法则:面向接口编程,而不是抽象编程。