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

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

个人博客,想要搭建个人博客的可以进来看看: 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 water
brew the tea
pour in cup
add lemon
Prepare the coffee...
boil the water
brew the coffee
pour in cup
add sugar and milk

Process 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());
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值