设计模式之模板方法

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬

学习必须往深处挖,挖的越深,基础越扎实!

阶段1、深入多线程

阶段2、深入多线程设计模式

阶段3、深入juc源码解析


阶段4、深入jdk其余源码解析


阶段5、深入jvm源码解析

码哥源码部分

码哥讲源码-原理源码篇【2024年最新大厂关于线程池使用的场景题】

码哥讲源码【炸雷啦!炸雷啦!黄光头他终于跑路啦!】

码哥讲源码-【jvm课程前置知识及c/c++调试环境搭建】

​​​​​​码哥讲源码-原理源码篇【揭秘join方法的唤醒本质上决定于jvm的底层析构函数】

码哥源码-原理源码篇【Doug Lea为什么要将成员变量赋值给局部变量后再操作?】

码哥讲源码【你水不是你的错,但是你胡说八道就是你不对了!】

码哥讲源码【谁再说Spring不支持多线程事务,你给我抽他!】

终结B站没人能讲清楚红黑树的历史,不服等你来踢馆!

打脸系列【020-3小时讲解MESI协议和volatile之间的关系,那些将x86下的验证结果当作最终结果的水货们请闭嘴】

模板方法

定义

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

(引用GoF 设计模式)

模板方法模型 是一种行为设计模型。 模板方法 是一个定义在父类别的方法,在 模板方法 中会呼叫多个定义在父类别的其他方法,而这些方法有可能只是抽象方法并没有实作, 模板方法 仅决定这些抽象方法的执行顺序,这些抽象方法的实作由子类别负责,并且子类别不允许覆写模板方法。

(引用维基百科)

类图

设计模式之模板方法_第1张图片

实现

1. 定义抽象类

    package template;
    
    /**
     * 抽象类: 作为基类,其子类必须实现抽象方法
     */
    public abstract class CaffeineBeverage {
        /**
         * 整个流程处理
         * 声明为final以免子类改变这个算法的顺序
         */
        final void prepareRecipe() {
            // 把水煮沸
            boilWater();
            // 用热水泡咖啡或茶
            brew();
            // 把饮料倒进杯子
            pourInCup();
            // 在饮料内加入适当的调料
            addCondiments();
        }
    
        abstract void brew();
        abstract void addCondiments();
    
        void boilWater() {
            System.out.println("boil water. Both.");
        }
    
        void pourInCup() {
            System.out.println("pour in cup. Both");
        }
    
    }

2. 定义实现类

    public class Coffee extends CaffeineBeverage{
    
        @Override
        void brew() {
            System.out.println("Coffee brew.");
        }
    
        @Override
        void addCondiments() {
            System.out.println("Coffee add sugar and milk.");
        }
    }
    public class Tea extends CaffeineBeverage {
        @Override
        void brew() {
            System.out.println("Tea brew.");
        }
    
        @Override
        void addCondiments() {
            System.out.println("Tea add lemon.");
        }
    }

回调

代码

1. 定义回调接口
    public interface ICallback {
        void methodToCallback();
    }
2.定义B类(接收回调函数者)
    public class BClass {
        public void process(ICallback callback) {
            callback.methodToCallback();
        }
    }
3.定义A类(传递回调函数者)
    /**
     * 1.回调跟模板模式一样,也具有复用和扩展的功能.
     * 2.回调分为同步回调、异步回调(延迟回调)。
     *   同步回调指在函数返回之前执行回调函数、异步回调指的是在函数返回之后执行回调函数。
     * 3.从应用场景看,同步模式看起来更像模式模式,异步回调看起来更像观察者模式。
     */
    public class AClass {
        public static void main(String[] args) {
            BClass b = new BClass();
            b.process(new ICallback() {
                @Override
                public void methodToCallback() {
                    System.out.println("method call back.");
                }
            });
        }
    }

回调小结

  1. 回调跟模板模式一样,也具有复用和扩展的功能。A类可以根据实际情况自定义实现回调方法。有具大的操作空间。

  2. 相对于普通的函数调用来说,回调是一种双向调用关系。A类事先注册某个函数F到B类,A类在调用B类的P函数的时候,B类反过来调用A类注册给它的F函数。即A调用B,B返过来调用A

  3. 应用举例:

    1. JdbcTemplate
    2. addShundownHook()
  4. 模块模式VS回调

    从应用场景上来看,同步回调跟模板模式几乎一致。它们都是在一个大的算法骨架中,自由替换其中的某个步骤,起到代码复用和扩展的目的。而异步回调跟模板模式有较大差别,更像是观察者模式。

    从代码实现上来看,回调和模板模式完全不同。回调基于组合关系来实现,把一个对象传递给另一个对象,是一种对象之间的关系;模板模式基于继承关系来实现,子类重写父类的抽象方法,是一种类之间的关系。

    组合优于继承。实际上,这里也不例外。在代码实现上,回调相对于模板模式会更加灵活,主要体现在下面几点。

    1. 像 Java 这种只支持单继承的语言,基于模板模式编写的子类,已经继承了一个父类,不再具有继承的能力。
    2. 回调可以使用匿名类来创建回调对象,可以不用事先定义类;而模板模式针对不同的实现都要定义不同的子类。
    3. 如果某个类中定义了多个模板方法,每个方法都有对应的抽象方法,那即便我们只用到其中的一个模板方法,子类也必须实现所有的抽象方法。而回调就更加灵活,我们只需要往用到的模板方法中注入回调对象即可。

总结

  1. 模板模式主要用来解决复用扩展问题。

    • 复用

      把一个算法中不变的流程抽象到父类的模板方法 templateMethod()中,将可变的部分method1()、method2()留给子类 ContreteClass1 和 ContreteClass2来实现。

      1. Java IO类库中,有很多设计用到了模板模式。如InputStream、OutputStream、Reader、Writer。在InputStream中,read()函数是一个模板方法,该方法定义了读取数据的整个流程,并且暴露了一个可以由子类定制的抽象方法。
      2. Java AbstractList类中。addAll()函数可以看作模板方法,虽然并未定义abstract抽象方法,但是函数直接抛出了异常。若要使用该方法,必须重写。
    • 扩展

      HttpServlet的 service()方法就是一个模板方法,它实现了整个 HTTP 请求的执行流程,doGet()、doPost()是模板中可以由子类来定制的部分。实际上,这就相当于Servlet框架提供了一个扩展点(doGet()、doPost() 方法),让框架用户在不用修改Servlet框架源码的情况下,将业务代码通过扩展点镶嵌到框架中执行。

      又比如compareTo方法。让子类扩展该方法的实现。

  2. 模块模式基于继承。对Java单继承语言来说,会有较大限制。

你可能感兴趣的:(设计模式,设计模式,模板方法)