设计模式连载3-模板方法模式

about templete patterns

Posted by 宸笙 on November 20, 2018

模式分类

从目的看

  1. 创建型
  2. 行为型
  3. 结构型

    从范围看

  4. 类模式
  5. 对象模式

    新分类

  6. 组件协作

    Template Method

    Strategy

    Observer/Event

  7. 单一职责

    Decorator

    Bridge

  8. 对象创建

    Factory Method

    Abstract Factory

    Prototype

    Builder

  9. 对象性能

    Singleton

    Flyweight

  10. 接口隔离

    Facade

    Proxy

    Adapter

    Mediator

  11. 状态变化

    State

    Memento

  12. 数据结构

    Composite

    Iterator

    Chain of Responsibility

  13. 行为变化

    Command

    Visitor

  14. 领域问题

    Interpreter

对设计模式的理解

  1. 对语言的补充

    在语言的特性角度

  2. 简洁的表达类似成语

    在表达上的角度

Refactoring to Patterns

  1. 面向对象设计模式是”好的面向对象设计”,指的是那些可以满足”应对变化,提高复用”的设计;
  2. 现代软件设计的特征是”需求的频繁变化”。设计模式的要点是”寻找变化点,然后在变化点处应用设计模式,从而更好的应对需求变化”,”什么时候,什么地点应用设计模式”比” 理解设计模式结构本身”更为重要;
  3. 设计模式的应用不宜先入为主,一上来就使用设计模式是对设计模式的最大误用。没有一步到位的设计模式。敏捷软件开发实践提倡的Refactoring to Patterns 是目前普遍公认的最好的使用设计模式的方法。

“组件协作”模式

  1. 现代软件专业分工之后的第一个结果是”框架与应用程序的划分”,”组件协作”模式通过晚期绑定,来实现框架与应用程序之间的松耦合,是二者之间协作时常用的模式。
  2. 典型模式:

    Templete Method

    Strategy

    Observer/Event

Templete Method(模板方法)

动机 Motivation

  1. 在软件构建过程中,对于某一项任务,它常常有稳定的整体操作结构,但各个字步骤却有很多改变的需求,或者由于固有的原因 比如框架于应用之间的关系 而无法和任务的整体结构同时实现;

  2. 如何在确定稳定操作结构的前提下,来灵活应对各个字步骤的变化或晚期实现需求?

Code Example

// 程序库开发人员
public Library{
    
    // 稳定
    public void step1(){
        // ...
    }
    // 稳定
    public void step3(){
        // ...
    }
    // 稳定
    public void step5(){
        // ...
    }
}

// 应用开发人员
public Application{
    
    // 变化
    public boolean step2(){
        // ... 
        return true;
    }
    
    // 变化
    public void step4(){
        // ...
    }
    
    // 稳定
    public static void main(String args[]){
        
        Library lib = new Library();
        
        Application app = new Application();
        
        // TODO: 问题在于以下算法步骤是稳定的
        lib.step1();
        
        if(app.step2()){
            lib.step3();
        }
        
        for(int i = 0; i < 4; i++){
            app.step4();
        }
        
        lib.step5();
    }
    
}

Refactoring

public abstract class Library{
    public void run(){ // 稳定 是谓模板方法
        
        step1();
        
        if(step2()){ // 支持变化,hook(多态)
            step3();
        }
        
        for(int i = 0; i < 4; i++){
            step4(); // 支持变化,hook(多态)
        }
        
        step5();
    }
    
    protected void step1(){ // 稳定 
        // ...
    }
    
    protected void step3(){ // 稳定
        // ...
    }
    
    protected void step5(){ // 稳定
        // ...
    }
    
    abstract boolean step2(); // 变化
    
    abstract void step4(); // 变化
    
}

// 应用程序开发人员
// 做的事情变少了-> 复用
public class Application extends Library{

    @Override
    protected boolean step2(){
        // ... 子类重写
        return true;
    }
    
    @Override 
    protected void step4(){
        // ... 子类重写
    }
    
    public static void main(String args[]){
        // 多态
        Library lib = new Application();
        lib.run();
    }
}

结构化软件设计流程

1 -> 2 -> 3 -> 4 -> 5

Library开发人员做的:

1,3,5

Application开发人员做的:

2,4

main process(主流程)

面向对象软件设计流程

1 -> 2 -> 3 -> 4 -> 5

Library开发人员做的:

1,3,5

main process

Application开发人员做的:

2,4

早绑定与晚绑定

时间先后 Library早 Application晚

  1. 早绑定

    Application -> Library

  2. 晚绑定

    Library -> Application

  3. 实现的机制

    虚函数的多态调用

看GOF中对Template Method的定义

定义一个操作中的算法的骨架(稳定),而将一些步骤延迟(变化)到子类中。使得子类可以不改变(复用)一个算法的结构即可重定义(override重写)该算法的某些特定步骤。

类图

AbstractClass

  • tm()
  • primitiveOperation1()
  • primitiveOperation2()

ConcreteClass

  • primitiveOperation1()
  • primitiveOperation2()

总结

  1. 是一种非常基础性的设计模式,在面向对象系统中有着大量的应用,用最简洁的机制(虚函数的多态性) 为很多应用程序框架提供了灵活的扩展点,是代码复用方面的基本实现结构;
  2. 除了可以灵活应对子步骤的变化外,”不要调用我,让我调用你”的反向控制结构也是该模式的典型应用;
  3. 在具体实现方面,被模板方法调用到的虚方法可以有具体实现,也可以没有,一般推荐protected修饰。

In Android

Activity

  • onCreate()
  • onStop()
  • onDestory()
  • onXxx()