设计模式之模板方法

模板方法

定义

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

(引用GoF 设计模式)

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

(引用维基百科)

类图

模板模式

实现

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()留给子类 ContreteClass1ContreteClass2来实现。

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

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

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

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

  3. 文章中内容分别来自Head First 设计模式图解设计模式设计模式之美(极客学院)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值