模板方法模式

时间:2022-04-26
本文章向大家介绍模板方法模式,主要内容包括概述、模板方法的组成、应用举例、模板方法的应用场景、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。

概述

概念:定义一个操作中算法的框架,而将一些步骤延迟到子类中,使得子类可以不改变算法的结构即可重定义该算法中的某些特定步骤。模板方法模式属于行为类模式。

模板方法的组成

类图:

如图所示,模板方法模式主要由AbstractClass(抽象类)和ConcreteClass(具体子类)组成。 AbstractClass(抽象类):定义一个模板,亦称为算法的“骨架”,在抽象类中定义了一系列基本操作(PrimitiveOperations),这些基本操作可以是具体的,也可以是抽象的,每一个基本操作对应算法的一个步骤,在其子类中可以重定义或实现这些步骤。同时,在抽象类中实现了一个模板方法(Template Method),用于定义一个算法的框架,模板方法不仅可以调用在抽象类中实现的基本方法,也可以调用在抽象类的子类中实现的基本方法,还可以调用其他对象中的方法。 ConcreteClass(具体子类):它是抽象类的子类,用于实现在父类中声明的抽象基本操作以完成子类特定算法的步骤,也可以覆盖在父类中已经实现的具体基本操作。

模式实现

模版方法模式由一个抽象类和一个(或一组)实现类通过继承结构组成,抽象类中的方法分为三种: 1)抽象方法:一个抽象方法由抽象类声明、由其具体子类实现。在C#语言里一个抽象方法以abstract关键字标识。 2)具体方法:一个具体方法由一个抽象类或具体类声明并实现,其子类可以进行覆盖也可以直接继承。 3)钩子方法:一个钩子方法由一个抽象类或具体类声明并实现,而其子类可能会加以扩展。通常在父类中给出的实现是一个空实现(可使用virtual关键字将其定义为虚函数),并以该空实现作为方法的默认实现,当然钩子方法也可以提供一个非空的默认实现。

应用举例

模板方式是我们开发中 遇到的常用方法。例如,某日,程序员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]);  
        }  
    }  
}  

然后项目经理将这分给另一个人,做了一个排序的功能,具体方法实现:

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;  
    }  
}  

客户端测试:

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

模板方法的应用场景

  1. 容易扩展。一般来说,抽象类中的模版方法是不易反生改变的部分,而抽象方法是容易反生变化的部分,因此通过增加实现类一般可以很容易实现功能的扩展,符合开闭原则。
  2. 便于维护。对于模版方法模式来说,正是由于他们的主要逻辑相同,才使用了模版方法,假如不使用模版方法,任由这些相同的代码散乱的分布在不同的类中,维护起来是非常不方便的。
  3. 比较灵活。因为有钩子方法,因此,子类的实现也可以影响父类中主逻辑的运行。但是,在灵活的同时,由于子类影响到了父类,违反了里氏替换原则,也会给程序带来风险。这就对抽象类的设计有了更高的要求。
  4. 其次, 在多个子类拥有相同的方法,并且这些方法逻辑相同时,可以考虑使用模版方法模式。在程序的主框架相同,细节不同的场合下,也比较适合使用这种模式