设计模式·模板方法

 

某种模式本质是依据设计原则由重构得到的 模板方法应对的是在一个固定的操作结构下,满足子步骤的变化 结构化设计重构到面向对象设计的过程 python的代码分析

  • 某种模式本质是依据设计原则由重构得到的
  • 模板方法应对的是在一个固定的操作结构下,满足子步骤的变化
  • 结构化设计重构到面向对象设计的过程
  • python的代码分析

Template Method 模式

缘起(Motivation)

  • 如何在确定稳定操作结构的前提下,来灵活应对各个子步骤的变化或者晚期实现需求
    • 在软件构建过程中
      • 对于某一项任务
      • 它常常有稳定的整体操作结构
      • 但各个子步骤却有很多改变的需求
      • 或者由于固有的原因(比如框架与应用之间的关系)而无法和任务的整体结构同时实现
  • 个人感觉叫框架方法/架构方法更贴切

设计

结构化设计

  • 库开发人员开发了一个lib,里面实现了完成某项工作的3个步骤

    //程序库开发人员
    class Library{
    
    public:
        void Step1(){ ... }
        void Step3(){ ... }
        void Step5(){ ... }
    };
    
  • 应用程序开发人员会调用库,并且自己再开发其中的2个步骤

    //应用程序开发人员
    class Application{
    public:
      bool Step2(){ //...  }
      void Step4(){ //...  }
    };
    
  • 应用程序开发人员还需要写好程序的执行流程

    int main()
    {
      Library lib();
      Application app();
    
      lib.Step1();
    
      if (app.Step2()){
          lib.Step3();
      }
    
      for (int i = 0; i < 4; i++){
          app.Step4();
      }
    
      lib.Step5();
    }
    

结构化设计,亦称SD(Structured Design),是一种面向数据流的设计方法,目的在于确定软件的结构 结构化分析 是一种面向功能或面向数据流的需求分析方法,采用自顶向下、逐层分解的方法,建立系统的处理流程。

面向对象设计

  • 库开发人员
    • 从设计整个对象的角度来写代码
      • 完成必需的step1、step3和step5功能
      • 同时把step2、step4也写下来,但不实现
    • 代码如下
      //程序库开发人员
      class Library{
      public:
        //稳定 template method
          void Run(){
              Step1();
      
              if (Step2()) { //支持变化 ==> 虚函数的多态调用
                  Step3(); 
              }
      
              for (int i = 0; i < 4; i++){
                  Step4(); //支持变化 ==> 虚函数的多态调用
              }
      
              Step5();
          }
        virtual ~Library(){ }
      
      protected:
        void Step1() { //稳定
              //.....
          }
        void Step3() {//稳定
              //.....
          }
        void Step5() { //稳定
          //.....
        }
      
        virtual bool Step2() = 0; //变化
        virtual void Step4() = 0; //变化
      };
      
  • 应用程序开发人员
    • 继承(复用)库
    • 实现变化的step2、step4

      //应用程序开发人员
      class Application : public Library {
      protected:
        virtual bool Step2(){
          //... 子类重写实现
          }
      
          virtual void Step4() {
          //... 子类重写实现
          }
      };
      
    • 在main中以固定套路写好调用框架

      int main() {
          Library* pLib=new Application();
          lib->Run();
          delete pLib;
      }
      
      • 通过子类创建了一个lib多态指针

区别

cm

  • 结构化设计中
    • 应用程序开发人员写了main函数即应用程序主流程
  • 面向对象设计
    • 程序主流程由库开发人员完成
  • 早绑定与晚绑定
    • 站在数据流的视角
    • 数据流经的各个方法是什么时候实现的
    • 早绑定是指
      • 晚的实现(应用程序函数)去调用早的实现(库函数)
      • 数据流经的一些方法,在库还中就已经绑定好了
    • 晚绑定是指
      • 早的实现(库函数)去调用晚实现(应用程序函数)
      • 数据流经的一些方法,在应用程序中才绑定

模式定义

  • 定义一个操作中的算法的骨架 (稳定),而将一些步骤延迟(变化)到子类中
    • 骨架
      • 库中的Run函数
    • 延迟
      • 让子类实现虚函数
      • 支持子类的变化
  • Template Method使得子类可以不改变(复用)一个算法的结构又可重定义(override 重写)该算法的某些特定步骤
    • 这种计模式的核心是稳定中有变化
    • 如果Run方法内容都是可变的或者都是稳定的,设计模式就没有意义了
  • 一个正常的软件体系
    • 既有变化点
    • 又有稳定点
  • 模式设计
    • 分辨出稳定点与变化点
    • 用代码实现划分

模板方法结构

要点总结

  • Template Method模式是一种非常基础性的设计模式,它用最简洁的机制(虚函数的多态性)为很多应用程序框架提供了灵活的扩展点,是代码复用方面的基本实现结构
    • 扩展点:继承 + 虚函数
  • 反向控制结构是Template Method的典型应用
    • 不要调用我,让我来调用你
    • 晚绑定

python 设计模式 - 模板方法

定义模板方法模式

  • 模板方法定义程序框架或算法
    • 模板方法使用抽象类来定义算法的步骤
    • 这些步骤在模板方法模式的上下文中也称为原始操作
    • 这些步骤通常用抽象方法定义
    • 模板方法则用来定义算法
  • 模板方法把步骤中的一些实现推迟到子类来帮助重新定义或定制算法的某些步骤

了解模板方法设计模式

  • 模板方法模式术语
    • AbstractClass:声明一个定义算法步骤的接口
    • ConcreteClass:定义子类特定的步骤
    • template_method():通过调用步骤方法来定义算法

模板方法模式的 UML 类图

  • AbstractClass
    • 在抽象方法的帮助下定义算法的操作或步骤
    • 这些步骤将被具体子类覆盖
  • template_method()
    • 定义算法的框架
    • 在模板方法中调用抽象方法定义的多个步骤来定义序列或算法本身
  • ConcreteClass
    • 实现(由抽象方法定义的)步骤,来执行算法子类的特定步骤
  • 举例
    • 为IOS开发一个交叉编译器
      • 首先开发编译器(抽象类):定义编译器的算法
        • 算法
          • 先收集代码(collectSoureces)
          • 再编译成bin(compile2Object)
          • 最后集中负责执行程序的run方法(compileAndRun)中
      • 然后具体类iOSCompiler实现抽象方法
      • 代码
        • 抽象类

          from abc import ABCMeta, abstractmethod
          
          class Compiler(metaclass=ABCMeta):
            @abstractmethod
            def collectSource(self):
              pass
            @abstractmethod
            def compileToObject(self):
              pass
            @abstractmethod
            def run(self):
              pass
            # 抽象类关键的是定义出了流程框架
            def compileAndRun(self):
              self.collectSource()
              self.compileToObject()
              self.run()
          
        • 具体类

          底层组件应当通过继承来调用高层组件

          class iOSCompiler(Compiler):
            def collectSource(self):
              print("Collecting Swift Source Code")
            def compileToObject(self):
              print("Compiling Swift code to LLVM bitcode")
            def run(self):
              print("Program runing on runtime environment")
          
        • 客户端(调用者)

          if __name__ == "__main__"
            iOS = iOSCompiler()
            iOS.compileAndRun()
          
    • 为旅行社开发不同的旅游路线
      • 定义抽象类Trip
        • 因为Trip活动有固定的流程
          • 设定好交通方式
          • 去目的地
          • 第1天
          • 第2天
          • 回家
        • 用行程组织上面的流程

          def itinerary(self):
            self.setTransport()
            self.day1()
            self.day2()
            self.day3()
            self.returnHome()
          
      • 根据要到的地方,实现不同的具体类
        • 广州Trip和深圳Trip
        • 它们要实现继承Trip中的具体方法

          class 广州Trip(Trip):
            def setTransport(self):
                print("Take a boat and find your way in the Grand Canal")
            def day1(self):
                print(....)
            ...
                  
          class 深圳Trip(Trip):
            ...
          
      • 使用Trip的客户端:旅行社

        class 旅行社:
          def 可选行程(self):
            choice = input("选择历史/现代")
        
            if choice == "历史":
              self.trip = 广州Trip()
            if choice == "深圳":
              self.trip = 深圳Trip()
        
            self.trip.行程()
        
      • 执行程序

        if __name__ == "__main__":
          旅行社.可选行程()