模板方法模式--我们一起下饺子

饺子制作的过程

小帅在外奔波多年,厌倦了程序员的生活,终于决定回老家安定下来,开了个饺子馆,天天下饺子。

小帅跟一个大厨苦练饺子制作,自己总结了一下饺子制作的过程:

擀面皮
包馅
水煮
出锅
加基本调料
加其他调料(顾客自行添加)

小帅就以这个流程为模板,在店里做各种各样的饺子,恩,生意还挺好的。

普通方法做饺子

小帅发挥程序员的特长,把做饺子的经过用代码写了下来,其实很简单:

制作韭菜馅饺子

/**
 * 韭菜馅饺子
 */
public class LeekDumpling {
    /**
     * 做饺子
     */
    public void makeDumpling() {
        // 擀面皮
        ganMianPi();
        // 包馅
        baoXian();
        // 水煮
        shuiZhu();
        // 出锅
        chuGuo();
        // 加基本调料
        jiaJiBenTiaoLiao();
        // 加其他调料
        jiaQiTaTiaoLiao();
    }

    // 擀面皮
    public void ganMianPi() {
        System.out.println("擀面皮");
    }

    // 包馅
    public void baoXian() {
        System.out.println("包韭菜馅");
    }

    // 水煮
    public void shuiZhu() {
        System.out.println("水煮8分钟");
    }

    // 出锅
    public void chuGuo() {
        System.out.println("出锅");
    }

    // 加基本调料
    public void jiaJiBenTiaoLiao() {
        System.out.println("加醋");
    }

    // 加其他调料
    public void jiaQiTaTiaoLiao() {
    }
}

制作猪肉馅饺子

/**
 * 猪肉馅饺子
 */
public class PorkDumpling {
    /**
     * 做饺子
     */
    public void makeDumpling() {
        // 擀面皮
        ganMianPi();
        // 包馅
        baoXian();
        // 水煮
        shuiZhu();
        // 出锅
        chuGuo();
        // 加基本调料
        jiaJiBenTiaoLiao();
        // 加其他调料
        jiaQiTaTiaoLiao();
    }

    // 擀面皮
    public void ganMianPi() {
        System.out.println("擀面皮");
    }

    // 包馅
    public void baoXian() {
        System.out.println("包猪肉馅");
    }

    // 水煮
    public void shuiZhu() {
        System.out.println("水煮10分钟");
    }

    // 出锅
    public void chuGuo() {
        System.out.println("出锅");
    }

    // 加基本调料
    public void jiaJiBenTiaoLiao() {
        System.out.println("加醋");
    }

    // 加其他调料
    public void jiaQiTaTiaoLiao() {
        System.out.println("加重辣");
    }
}

在这里插入图片描述

在这里插入图片描述
小帅的店里不仅有韭菜馅饺子,猪肉馅饺子还有牛肉馅,蘑菇馅,海鲜馅饺子等等十几种呢,各种饺子的制作过程其实都是大同小异,主要是包的馅不一样,然后就水煮的时间不一样。

如果每种饺子都各自实现一次所有的代码,会出现大量的重复代码,该怎么改进呢?

模板方法做饺子

其实每种饺子的制作都是按固定的流程制作的,这种情况就非常适合使用模板方法模式。

模板方法模式定义如下:模板方法模式在一个方法中定义一个算法骨架,并将某些步骤推迟到子类中实现。模板方法模式可以让子类在不改变算法整体结构的情况下,重新定义算法中的某些步骤。

类图如下:
在这里插入图片描述

按照模板方法模式改造一下:

饺子抽象类

public abstract class Dumpling {

    /**
     * 做饺子
     */
    public final void makeDumpling() {
        // 擀面皮
        ganMianPi();
        // 包馅
        baoXian();
        // 水煮
        shuiZhu();
        // 出锅
        chuGuo();
        // 加基本调料
        jiaJiBenTiaoLiao();
        // 钩子
        hook();
    }

    /**
     * 擀面皮
     */
    public void ganMianPi() {
        System.out.println("擀面皮");
    }

    /**
     * 包馅(抽象方法需要在子类中实现)
     */
    public abstract void baoXian();

    /**
     * 水煮(抽象方法需要在子类中实现)
     */
    public abstract void shuiZhu();

    /**
     * 出锅
     */
    public void chuGuo() {
        System.out.println("出锅");
    }

    /**
     * 加基本调料
     */
    public void jiaJiBenTiaoLiao() {
        System.out.println("加醋");
    }

    /**
     * 钩子(自定义扩展方法,默认实现为空)
     */
    public void hook() {
    }

}

韭菜馅饺子

/**
 * 韭菜馅饺子
 */
public class LeekDumpling extends Dumpling{

    /**
     * 包馅
     */
    @Override
    public void baoXian() {
        System.out.println("包韭菜馅");
    }

    /**
     * 水煮
     */
    @Override
    public void shuiZhu() {
        System.out.println("水煮8分钟");
    }
}

猪肉馅饺子

/**
 * 猪肉馅饺子
 */
public class PorkDumpling extends Dumpling{

    /**
     * 包馅
     */
    @Override
    public void baoXian() {
        System.out.println("包猪肉馅");
    }

    /**
     * 水煮
     */
    @Override
    public void shuiZhu() {
        System.out.println("水煮10分钟");
    }


    /**
     * 覆盖hook()方法,加其他调料
     */
    @Override
    public void hook() {
        System.out.println("加重辣");
    }
}

制作饺子

public class MakeDumpling {

    public static void main(String[] args) {
        // 制作韭菜馅饺子
        System.out.println("制作韭菜馅饺子");
        LeekDumpling leekDumpling = new LeekDumpling();
        leekDumpling.makeDumpling();

        System.out.println();
        // 制作猪肉馅饺子
        System.out.println("制作猪肉馅饺子");
        PorkDumpling porkDumpling = new PorkDumpling();
        porkDumpling.makeDumpling();
    }
}

输出结果

制作韭菜馅饺子
擀面皮
包韭菜馅
水煮8分钟
出锅
加醋

制作猪肉馅饺子
擀面皮
包猪肉馅
水煮10分钟
出锅
加醋
加重辣

在这里插入图片描述

饺子的固定制作过程,擀面皮【ganMianPi()】,出锅【chuGuo()】, 加基本调料【jiaJiBenTiaoLiao()】每种饺子都是一样的,所以直接在父类中实现,实现了代码的复用。

包馅【baoXian()】,水煮【shuiZhu()】每种饺子都不一样,定义为抽象方法,具体的操作推迟到子类中实现。

钩子【hook()】方法比较有意思,在父类中默认实现为空,如果子类有什么特殊的操作,父类中没有定义的,那么子类就可以覆盖hook(),实现自己扩展的业务逻辑。

比如加辣椒,不是每个客人都喜欢吃辣的,那么需要加辣椒的顾客自己覆盖hook()方法,加上辣椒就行了,不需要加辣椒的顾客就不用重写hook()方法了。

总结

在模板模式经典的实现中,模板方法定义为 final,可以避免被子类重写。
需要子类重写的方法定义为 abstract,可以强迫子类去实现。
如果子类需要扩展,可以预留一个hook()的空实现方法,让需要的子类去重写。

该模式应用了好莱坞原则:别调用(打电话给)我们,我们会调用(打电话给)你

换句话说就是:子类你别调用我们(父类),我们(父类)会调用你。

模板模式有两大作用:复用和扩展

复用指的是,所有的子类可以复用父类中提供的模板方法的代码。

扩展指的是,框架通过模板模式提供功能扩展点,也就是钩子hook(),让框架用户可以在不修改框架源码的情况下,基于扩展点定制化框架的功能。

代码链接
(欢迎关注公众号:编程我也会)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值