设计模式-----模板方法模式

来源:互联网 发布:美蓝漫画无法连接网络 编辑:程序博客网 时间:2024/06/08 03:06

设计模式—–模板方法模式

个人博客,想要搭建个人博客的可以进来看看: http://www.ioqian.top/


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

设计模式系列博客代码: https://github.com/liloqian/DesiginModeDemo

背景 , 我们的生活过程中,煮茶和咖啡的工作看起来不同,但是都可以分为下面4步,烧水,把茶或者咖啡放入水中,把咖啡或者水放到杯子中,加入调料,我们可以把公共的操作步骤提取出来放在抽象类中,不同的部分放在子类去实现

1.UML
此处输入图片的描述

  • AbstractClass 抽象父类部分,背景中的烧水喝倒入杯子等固定的动作放在抽象父类实现
  • ConcreteClass 具体实现类 , 茶还是咖啡,加糖还是柠檬让具体子类实现

最使用模板方法中,只需要调用具体实现类的模板方法就可以

2.代码

AbstractClass

/**抽象父类*/public abstract class CaffeineBeverage {    /**模板方法,对外提供的接口*/    public final void prepareRecipe() {        boilWater();        brew();        pourInCup();        addCondiments();    }    //改变的部分让子类去实现    abstract void brew();    abstract void addCondiments();    //固定的部分直接实现,使用private关键字让外部无法调用    // final关键字是让子类重写改变这个方法    private final void boilWater() {        System.out.println("boil the water");    }    private final void pourInCup() {        System.out.println("pour in cup");    }}

具体类

/**具体模板类,实现了tea特性的操作*/public class Tea extends CaffeineBeverage {    @Override    void brew() {        System.out.println("brew the tea");    }    @Override    void addCondiments() {        System.out.println("add lemon");    }}//和上面相同public class Coffee extends CaffeineBeverage {    @Override    void brew() {        System.out.println("brew the coffee");    }    @Override    void addCondiments() {        System.out.println("add sugar and milk");    }}

测试Main

public class Main {    public static void main(String[] args) {        //准备tea        System.out.println("Prepare the tea ...");        CaffeineBeverage tea = new Tea();        tea.prepareRecipe(); //只要调用模板的方法,不关心怎么实现的        //准备coffee        System.out.println("Prepare the coffee...");        CaffeineBeverage coffee = new Coffee();        coffee.prepareRecipe();    }}//结果Prepare the tea ...boil the waterbrew the teapour in cupadd lemonPrepare the coffee...boil the waterbrew the coffeepour in cupadd sugar and milkProcess finished with exit code 0

3.总结

  • 模板抽象类是对外提供了唯一的算法,并且使用final关键字保护了这个算法,在以后算法的修改时,仅仅改这一处就可以了
  • 模板抽象类实现了共同的操作,将代码复用最大化
  • 模板方法提供了一个框架,让其他的具体实现者来实现细节

4.模板方法模式中的钩子

改进,使用钩子hook(),在上面的背景例子中,咖啡和茶的都可以抽象为4个步骤,但是当存在一种实例只有3中步骤,比如可乐就不需要烧水操作,我们应该怎样把他们统一到模板方法中,这个时候就可以使用钩子了

改变抽象类方法

/**抽象父类*/public abstract class CaffeineBeverage {    /**模板方法,对外提供的接口*/    public final void prepareRecipe() {        //通过一个方法判断是否需要烧水,直接实现中返回true,但是当可乐时可以重写  isNeedBoilWater()返回false        if(isNeedBoilWater()){            boilWater();        }        brew();        pourInCup();        addCondiments();    }    //改变的部分让子类去实现    abstract void brew();    abstract void addCondiments();    //固定的部分直接实现,使用private关键字让外部无法调用    // final关键字是让子类重写改变这个方法    private final void boilWater() {        System.out.println("boil the water");    }    private final void pourInCup() {        System.out.println("pour in cup");    }    //-----changed-----不是final让子类可以改变    private boolean isNeedBoilWater(){        return true;    }}

看了上面的代码,应该对钩子有了理解了,isNeedBoilWater()就是钩子方法;当我们创建一个模板方法时,如果子类必须实现的一个方法就是有抽象方法,如果这个方法时可选的就使用钩子

5.模板方法模式中的好莱坞原则

好莱坞原则 , 别调用我们,我们会调用你;高层组件调用底层组件,底层组件不要去调用高层组件

看起来很懵逼,不知道什么意思。结合我们的模板方法模式来理解一下,我们的抽象父类(高层组件)调用了具体实现类(底层组件)的方法,这里具体实现类实现了抽象方法,但是抽象具体类不可以调用抽象父类的方法

6.模板方法模式在JDK中的使用

我们都知道集合是我们常用的一个类,大部分集合是可以排序的,比如说ArrayList,可以对ArrayList中的成员进行排序,但是不是每种存储在ArrayList中的类都可以排序的,可以排序的类必须实现了Comparable接口(public int compareTo(T o);唯一的方法),我们在使用Double,Integer中直接可以排序是因为这些类继承了Comparable接口的,可以去看看源码,这就是一个模板方法模式的使用

/**继承了Comparable接口,Duck类可以使用sort方法*/public class Duck implements Comparable{    //在comparTo()中使用这个int类型排序    int weight;    public Duck(int weight) {        this.weight = weight;    }    @Override    public int compareTo(Object o) {        Duck oDuck = (Duck) o;        if(this.weight > oDuck.weight){            return 1;        }else if(this.weight == oDuck.weight){            return 0;        }else {            return  -1;        }    }    //重写了toString()后面的打印中使用    @Override    public String toString() {        return "my weight is " + this.weight;    }    //测试main    public static void main(String[] args) {        //new个ArrayList        List<Duck> ducks = new ArrayList<>();        for(int i =0 ; i < 10 ;i++){            ducks.add(new Duck((int)(Math.random()*100)));        }        //未排序前打印集合信息        show(ducks);        System.out.println("\n\n");        //排序        Collections.sort(ducks);        //排序后再次打印        show(ducks);    }    //打印集合信息    private static void show(List<Duck> lists){        for (Duck duck : lists) {            System.out.println(duck.toString());        }    }}
原创粉丝点击