模板方法模式

来源:互联网 发布:react.js api 编辑:程序博客网 时间:2024/06/07 08:17

模板方法模式,在一个方法中定义了一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

举个栗子:

在某个饮品店中,有如下两种饮料(咖啡和饮料)的泡法:

1、咖啡的泡法如下:

(1)把水煮沸

(2)用沸水冲泡咖啡

(3)把咖啡倒进杯子

(4)加糖和牛奶

2、茶的泡法如下:

(1)把水煮沸

(2)用沸水浸泡茶叶

(3)把茶倒进杯子

(4)加柠檬

不推荐的Java代码实现如下:

Coffee.java 类如下:

/** *  咖啡类,用来煮咖啡 */public class Coffee {    // 咖啡冲泡法    void prepareRecipe(){        boilWater();        brewCoffeeGrinds();        pourInCup();        addSugarAndMilk();    }    // 煮沸水    public void boilWater(){        System.out.println("Boiling water");    }    // 冲泡咖啡    public void brewCoffeeGrinds(){        System.out.println("Dripping Coffee through filter");    }    // 把咖啡倒进杯子    public void pourInCup(){        System.out.println("Pouring into cup");    }    // 加糖和奶    public void addSugarAndMilk(){        System.out.println("Adding Sugar and Milk");    }}

Tea.java 类如下:

/** *  茶类,用来冲泡茶 */public class Tea {    // 茶的冲泡法    void prepareRecipe(){        boilWater();        steepTeaBag();        pourInCup();        addLemon();    }    // 煮沸水    public void boilWater(){        System.out.println("Boilling water");    }    // 冲泡茶    public void steepTeaBag(){        System.out.println("Steep the tea");    }    // 把茶倒进杯子    public void pourInCup(){        System.out.println("Pouring into cup");    }    // 加柠檬    public void addLemon(){        System.out.println("Adding Lemon");    }}

分析:

我们发现上述代码中有很多重复的代码,他们的泡法很类似,因此,我们可以将共同的部分放在一个基类中。

推荐利用模板方法模式:

提取出来的模板方法CaffeineBeverage.java 类:

public abstract class CaffeineBeverage {    final void prepareRecipe(){        boilWater();        brew();        pourInCup();        addCondiments();        hook();    }    abstract void brew();    abstract void addCondiments();    void boilWater(){        System.out.println("Boiling water");    }    void pourInCup(){        System.out.println("Pouring into cup");    }    /**     *  这是一个具体方法(它什么事情都不做)     */    void hook(){    }}

两个具体的实现类如下:

Coffee.java 类:

public class Cofffe extends CaffeineBeverage {    @Override    void brew() {        System.out.println("Dripping Coffee through filter");    }    @Override    void addCondiments() {        System.out.println("Adding Sugar and Milk");    }}

Tea.java 类如下:

public class Tea extends CaffeineBeverage {    @Override    void brew() {        System.out.println("Steeping the tea");    }    @Override    void addCondiments() {        System.out.println("Adding Lemon");    }}

分析:模板方法模式:

(1)为我们提供了一种代码复用的重要技巧。

(2)在模板方法的抽象类中可以定义具体方法、抽象方法和钩子,其中,抽象方法由子类事项。钩子,是一种方法,它在抽象类中不做事,或者制作默认的事情,子类可以选择要不要去覆盖它。钩子和具体方法看起来很像,但是具体方法子类子继承时无需覆盖(因为是所有子类的共同部分),而钩子子类可能需要覆盖。

(3)为了防止子类改变模板方法中的算法,可以将模板方法声明为final

(4)关于抽象类的具体用法可以同样参考我这篇博文:Java抽象类中变与不变的行为设计

原创粉丝点击