设计模式学习笔记——模板方法模式

概述

模板方法定义了一个算法的步骤,并允许子类为一个或多个步骤提供实现。

认识模板方法

选自Head First一个例子,很好理解该模式。
需求:咖啡店有两个饮料冲泡法,分别为咖啡冲泡法、茶叶冲泡法。
咖啡冲泡法:
(1)把水煮沸
(2)用沸水冲泡咖啡
(3)把咖啡倒进杯子
(4)加糖和牛奶

public class Coffee

void prepareRecipe(){
    boilWater();
    brewCoffeeGrinds();
    PourIncup();
    addSugarAndMilk();
}
//具体实现……

茶叶冲泡法:
(1)把水煮沸
(2)用沸水浸泡茶叶
(3)把茶倒进杯子
(4)加柠檬

public class Tea

void prepareRecipe(){
    boilWater();
    steepTeaBag();
    PourIncup();
    addLemon();
}
//具体实现……

我们注意到两份冲泡法都采用了相同的算法
(1)把水煮沸
(2)用热水泡咖啡或茶
(3)把饮料倒进杯子
(4)在饮料内加入适当的调料
我们可以在超类中抽象出来prepareRecipe方法,如下:

public abstract class CaffeineBeverage
{
    final void prepareRecipe(){
        boilWater();
        brew();
        pourIncup();
        addCondiments();
    }
    abstract void brew();
    abstract void addCondiments();
    void boilWater(){
        System.out.println("Boiling water");
    }
    voud pourInCup(){
        System.out.println("Pouring into cup");
    }
}

子类实现步骤:

public class Tea extends CaffenieBeverage{
    public void brew(){
        System.out.println("Steeping the tea");
    }
    public void addCondiments(){
        System.out.println("Add8hg Lemon");
    }
}

定义

模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
这个模式用来创建一个算法的模板,模板就是一个方法,这个方法将算法定义成一组步骤,其中的任何步骤都可以是抽象的,由子类负责实现。这确保算法的结构保持不变,同时又子类提供部分实现。

模板方法进阶

abstract class AbstractClass{
    final void templateMethod(){
        primitiveOperation1();
        primitiveOperation2();
        concreteOperation();
        hook();
    }
    abstract void primitiveOperation1();
    abstract void primitiveOperation2();
    final void concreteOperation(){
        //实现
    }
    void hook(){
        //啥都不做,钩子
    }
}

其中钩子是不同于上面的普通模板方法,钩子可以让用户决定要不要覆盖方法。

钩子用法之——控制流程

如:

public abstract class CaffeineBeverageWithHook
{
    final void prepareRecipe(){
        boilWater();
        brew();
        pourIncup();
        //见下(1)
        if(customerWantsCondiments()){
            addCondiments();
        }
    }
    abstract void brew();
    abstract void addCondiments();
    void boilWater(){
        System.out.println("Boiling water");
    }
    voud pourInCup(){
        System.out.println("Pouring into cup");
    }
    //见下(2)
    boolean customerWantsCondiments(){
        return true;
    }
}

注意区别:
(1)我们加上了一个小小的条件语句,而该条件是否成立,由一个具体方法customerWantsCondiments()决定。
(2)我们在下面定义了一个方法,是空的缺省实现。这个方法只返回True。这就是一个钩子,子类可以覆盖这个方法,但不见得一定要这么做。

钩子的其他用法

让子类能够有机会对模板方法中某些即将发生的(或刚刚发生的)步骤作出反应。
比如:
名为justReOrderedList()的钩子方法允许子类在内部列表重新组织后执行某些动作(例如在屏幕上重新显示数据)。

举例

Android中的Activity的生命周期控制函数,如onCreate,onStop,onResume,onDestroy方法等,它们都属于钩子,钩子默认不进行任何操作。我们可以通过覆写这些方法,进行我们自己的业务逻辑。

好莱坞原则

别调用我们,我们会调用你。
好莱坞原则可以给我们一钟防止”依赖腐败”的方法。当高层组件依赖底层组件,而底层组件又依赖高层组件,而高层组件又依赖边侧组件,而边侧组件又依赖底层组件时,依赖腐败就发生了。
好莱坞原则就是高层组件对待底层组件的方式是别调用我们,我们会调用你

JAVA API中的模板方法

如:Arrays.sort(Object[] arrays)方法,它实现了对一个对象数组进行排序,大致源码如下:

public static void sort(Object[] a){
    Object aux[] = (Object[] )a.clone();
    mergeSort(aux,a,0,a.length,0);
}
public static void mergeSort(Object[] src[],Object dest[],int low,int high,int off){
    for(int i = low + off ; i < high ; i++){
        for(int j = i ; j > low &&((Comparable)dest[j-1].compareTo((Comparable)dest[j]>0);j--){
            swap(dest,j,j-1);
        }
    }
    return;
}

其中sort是暴露出来的静态方法,实则调用了mergeSort()方法,这就是一个模板方法,它规定了一个算法,但sort方法需要知道排序的规则(即知道两个对象谁大谁小),所以该对象必须实现一个接口——Comparable
如下:

public class person implements Comparable{
    String name;
    int age;
    //setter getter ....
    public int compareTo(Object object){
        Person p = (Person) object;
        if(this.age < p.age){
            return -1;
        }
        else if(this.age == p.age){
            return 0;
        }
        else{
            return 1;
        }
    }
}

Person实现了Comparable接口,则可以进行用compareTo方法进行比较大小,故可以使用Arrays.sort()方法进行排序。

该方法是一种简单的模板方法,模板方法并不一定都需要子类去继承或实现算法,模板方法只是提供一个算法骨架。sort方法希望能够适用于所有的数组,所以它们定义了一个静态方法,而由被排序的对象内的每个元素自行提供比较大小的算法部分,它的实现符合模板方法的精神。

其他的模板方法:InputStream中的read方法,它是由子类实现的,而这个方法又会被read(byte b[],int off,int len)模板方法使用。

猜你喜欢

转载自blog.csdn.net/u012525096/article/details/80781040