Java设计模式设计模式

《设计模式》模板方法模式

2019-08-12  本文已影响5人  敏捷Studio

定义

定义一个操作中的算法框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义算法的某些特定步骤。

介绍

UML类图

模板方法UML类图

角色说明:

实现

继续以送快递为例,快递员送快递基本就是一套固定的流程:收到快递,准备派送->联系收货人->确定结果。

1、创建抽象类。定义算法框架,这里是快递员派送快递的步骤:

// 抽象快递员类
public abstract class Postman {

  // 派送流程。(这里申明为final,不希望子类覆盖这个方法,防止更改流程的执行顺序)
  public final void post() {
    // 准备派送
    prepare();
    // 联系收货人
    call();
    if (isSign()) {
      // 签收
      sign();
    } else {
      // 拒签
      refuse();
    }
  }

  // 准备操作,固定流程,父类实现
  protected void prepare() {
    System.out.println("快递已达到,准备派送");
  }

  // 联系收货人,联系人不一样,所以为抽象方法,子类实现
  protected abstract void call();

  // 是否签收,这个是钩子方法,用来控制流程的走向
  protected boolean isSign() {
    return true;
  }
  
  // 签收,这个是固定流程,父类实现
  protected void sign() {
    System.out.println("客户已签收,上报系统");
  }

  // 拒签,空实现,这个也是钩子方法,子类可以跟进实际来决定是否去实现这个方法
  protected void refuse() {
  }
}

需要注意的是上面的抽象类(Postman)包含了三种类型的方法:抽象方法、具体方法和钩子方法。

2、创建具体实现类。根据需要去实现抽象类中的方法,下面以派送给两个不同的人为例,其中一个签收,另一个拒收:

// 派送给A先生
public class PostA extends Postman {
  // 联系收货,实现父类的抽象方法
  @Override
  protected void call() {
    System.out.println("联系A先生并送到门口");
  }
}

// 派送给B先生
public class PostB extends Postman {
  // 联系收货,实现父类的抽象方法
  @Override
  protected void call() {
    System.out.println("联系B先生并送到门口");
  }

  // 是否签收,覆盖父类的钩子方法,控制流程的走向
  @Override
  protected boolean isSign() {
    return false;
  }

  // 拒签,覆盖父类的钩子方法
  @Override
  protected void refuse() {
    System.out.println("拒绝签收:商品不符");
  }
}

3、客户端测试

public void test() {
  System.out.println("----派送A----");
  Postman postA = new PostA();
  postA.post();
  System.out.println("----派送B----");
  Postman postB = new PostB();
  postB.post();
}

输出结果:

----派送A----
快递已达到,准备派送
联系A先生并送到门口
客户已签收,上报系统
----派送B----
快递已达到,准备派送
联系B先生并送到门口
拒绝签收:商品不符

应用场景

优缺点

优点

缺点

Android中的源码分析

AndroidViewdraw()方法就是使用了模板方法模式:

1、Viewdraw()方法

public class View {
  // 钩子方法,空实现
  protected void onDraw(Canvas canvas) {
  }

  // 钩子方法,空实现
  protected void dispatchDraw(Canvas canvas) {
  }

  // 绘制方法,定义绘制流程
  public void draw(Canvas canvas) {
    // 其他代码略

    /**
     *  绘制流程如下:
     *
     *      1. 绘制view背景
     *      2. 如果有需要,就保存图层
     *      3. 绘制view内容
     *      4. 绘制子View
     *      5. 如果有必要,绘制渐变框和恢复图层
     *      6. 绘制装饰(滑动条等)
     */

    // 步骤1. 绘制view背景
    if (!dirtyOpaque) {
      drawBackground(canvas);
    }

    // 如果可能的话跳过第2步和第5步(常见情况)
    final int viewFlags = mViewFlags;
    boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;
    boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;
    if (!verticalEdges && !horizontalEdges) {
      // 步骤3. 绘制view内容
      if (!dirtyOpaque) onDraw(canvas);

      // 步骤4. 绘制子View
      dispatchDraw(canvas);

      // 覆盖一部分内容,绘制前景
      if (mOverlay != null && !mOverlay.isEmpty()) {
        mOverlay.getOverlayView().dispatchDraw(canvas);
      }

      // 步骤6. 绘制装饰(滑动条等)
      onDrawForeground(canvas); 

      return;
    }
  }
}

2、说明

3、其他
另外,像Activity的生命周期,AsyncTask等等也是用到了模板方法模式,也兴趣的可以研究一下。

上一篇 下一篇

猜你喜欢

热点阅读