• 《设计模式之美》


    一、模板模式

    我们多次强调,绝大部分设计模式的原理和实现,都非常简单,难的是掌握应用场景,搞清楚能解决什么问题。模板模式也不例外。模板模式主要是用来解决复用和扩展两个问题。模板方法模式在一个方法中定义一个算法骨架,并将某些步骤推迟到子类中实现。模板方法模式可以让子类在不改变算法整体结构的情况下,重新定义算法中的某些步骤。这里的“算法”,我们可以理解为广义上的“业务逻辑”,并不特指数据结构和算法中的“算法”。这里的算法骨架就是“模板”,包含算法骨架的方法就是“模板方法”,这也是模板方法模式名字的由来。示例代码:

    public abstract class AbstractClass {
      public final void templateMethod() {
        //...
        method1();
        //...
        method2();
        //...
      }
      
      protected abstract void method1();
      protected abstract void method2();
    }
    
    public class ConcreteClass1 extends AbstractClass {
      @Override
      protected void method1() {
        //...
      }
      
      @Override
      protected void method2() {
        //...
      }
    }
    
    public class ConcreteClass2 extends AbstractClass {
      @Override
      protected void method1() {
        //...
      }
      
      @Override
      protected void method2() {
        //...
      }
    }
    
    AbstractClass demo = ConcreteClass1();
    demo.templateMethod();
    

      在模板模式经典的实现中,模板方法定义为 final,可以避免被子类重写。需要子类重写的方法定义为 abstract,可以强迫子类去实现。不过,在实际项目开发中,模板模式的实现比较灵活,以上两点都不是必须的。

    复用和扩展是模板模式的两大作用,实际上,还有另外一个技术概念,也能起到跟模板模式相同的作用,那就是回调(Callback)。今天我们今天就来看一下,回调的原理、实现和应用,以及它跟模板模式的区别和联系。

    二、回调

    回调的原理解析相对于普通的函数调用来说,回调是一种双向调用关系。A 类事先注册某个函数 F 到 B 类,A 类在调用 B 类的 P 函数的时候,B 类反过来调用 A 类注册给它的 F 函数。这里的 F 函数就是“回调函数”。A 调用 B,B 反过来又调用 A,这种调用机制就叫作“回调”。

    A 类如何将回调函数传递给 B 类呢?不同的编程语言,有不同的实现方法。C 语言可以使用函数指针,Java 则需要使用包裹了回调函数的类对象,我们简称为回调对象。这里我用 Java 语言举例说明一下。代码如下所示:

    public interface ICallback {
      void methodToCallback();
    }
    
    public class BClass {
      public void process(ICallback callback) {
        //...
        callback.methodToCallback();
        //...
      }
    }
    
    public class AClass {
      public static void main(String[] args) {
        BClass b = new BClass();
        b.process(new ICallback() { //回调对象
          @Override
          public void methodToCallback() {
            System.out.println("Call back me.");
          }
        });
      }
    }

    回调可以分为同步回调和异步回调(或者延迟回调)。同步回调指在函数返回之前执行回调函数;异步回调指的是在函数返回之后执行回调函数。上面的代码实际上是同步回调的实现方式,在 process() 函数返回之前,执行完回调函数 methodToCallback()。而上面支付的例子是异步回调的实现方式,发起支付之后不需要等待回调接口被调用就直接返回。从应用场景上来看,同步回调看起来更像模板模式,异步回调看起来更像观察者模式。

    三、模板 VS 回调

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

    回调基于组合关系来实现,把一个对象传递给另一个对象,是一种对象之间的关系;模板模式基于继承关系来实现,子类重写父类的抽象方法,是一种类之间的关系。前面我们也讲到,组合优于继承。实际上,这里也不例外。在代码实现上,回调相对于模板模式会更加灵活,主要体现在下面几点。

    • 像 Java 这种只支持单继承的语言,基于模板模式编写的子类,已经继承了一个父类,不再具有继承的能力。回调可以使用匿名类来创建回调对象,可以不用事先定义类;而模板模式针对不同的实现都要定义不同的子类。
    • 如果某个类中定义了多个模板方法,每个方法都有对应的抽象方法,那即便我们只用到其中的一个模板方法,子类也必须实现所有的抽象方法。而回调就更加灵活,我们只需要往用到的模板方法中注入回调对象即可。 
  • 相关阅读:
    二叉排序树和平衡二叉树
    博客首页特效整理2
    博客首页特效整理
    19-20下学期思维导图
    19-20下学期第一次作业问卷调查回答
    c++实现五子棋游戏
    c++实现扫雷游戏
    c++实现2048游戏
    c++实现推箱子游戏
    C++实现贪吃蛇小游戏
  • 原文地址:https://www.cnblogs.com/sunada2005/p/14393984.html
Copyright © 2020-2023  润新知