# 1.模板方法模式

## Template Method（模板方法）

在日常的开发中，模板方法是一种用于流程封装的设计模式

比如，类似的功能或许具体的实现细节不一样，但是功能的执行流程是一样的，这时通过将执行流程封装起来，那么在使用这种模式的时候，只需要去关注如何实现功能细节就可以了。这样将公共代码提取出来，便于维护。

## Template Method（模板方法）的UML类图

![](https://raw.githubusercontent.com/InnoFang/DesignPatterns/master/uml/template_method.png)

* AbstractClass : 抽象模板，定义了模板方法的执行流程
* ConcreteClass : 具体实现类

## 模板方法的简单实现

如果非要说一个现实中的案例的话，我觉可以例举工厂中的流水线 (Assembly Line)

因为一条流水线的分工是明确的，流水线的头部是加工元器件，中部是元器件装配，尾部就是将电子产品打包装箱，这是流水线作业的流程，但是具体是装配什么电子产品，需要在那个流程上注意什么细节，每一条流水线都是不一样的，如果开发者需要开发类似的功能，利用模板方法模式是再合适不过的了

经过上面的介绍，下面就来实现以下这个案例

首先就是对流水线作业流程进行抽象

```java
public abstract class AssemblyLine {
    /* 生产产品外壳 */
    protected void onProduceShell() {
        System.out.println("Produce Shell");
    }
    /* 生产元器件 */
    protected void onProduceComponents() {
        System.out.println("Produce some components");
    }
    /* 元器件装配 */
    protected void onAssemblyComponents() {
        System.out.println("Assembly Components");
    }
    /* 产品测试 */
    protected void onTestProducts(){
        System.out.println("Test Products");
    }
    /* 产品装箱 */
    protected void onProductPacking() {
        System.out.println("Product Packing");
    }
    /* 流水线产品制作流程封装 */
    public final void product() {
        System.out.println("+------Start Product------+");
        onProduceShell();
        onProduceComponents();
        onAssemblyComponents();
        onTestProducts();
        onProduceComponents();
        onProductPacking();
        System.out.println("+------Finish Product------+");
    }
}
```

在流水线作业中，我将具体流程分成了上面五个部分：

* 生产产品外壳
* 生产元器件
* 元器件装配
* 产品测试
* 产品装箱

并且对于流水线的执行流程的代码使用了 final 修饰，这样子类就不可以重写这个方法

为了简单起见，内部方法的实现用一句输出代替，但是具体实现细节应该根据具体情况而定，因为这种流程式的功能设计，或多说少都会有共有的实现，那么就可以将共有代码写在抽象类的对应方法内部

如果这是一家电子产品生产厂的流水线，那么就会各种各样的电子产品，那么这里例举生产收音机的流水线和生产电脑的流水线，其他情况可以自行拓展

生产收音机的流水线

```java
public class RadioAssemblyLine extends AssemblyLine {
    /* 生产收音机元器件和天线 */
    @Override
    protected void onProduceComponents() {
        System.out.println("Product Radio Components and Antennas");
    }
}
```

在这里，只重写了一个生产元器件的方法

再来看一下生产电脑的流水线，为了区分与生产收音机的流水线，这里多重写几个方法

```java
public class ComputerAssemblyLine extends AssemblyLine {
    /* 生产铝合金外壳和液晶显示屏 */
    @Override
    protected void onProduceShell() {
        System.out.println("Product Aluminum housing and Liquid Crystal Display");
    }
    /* 生产元器件和键盘 */
    @Override
    protected void onProduceComponents() {
        System.out.println("Product Components and keyboard");
    }
    /* 将产品打包并标上苹果标签 */
    @Override
    protected void onProductPacking() {
        System.out.println("Pack and Mark the Apple trademark");
    }
}
```

这里多重写了产品装配方法和产品打包方法

可以看到的是，在这两个具体的流水线中，都只写了区别于其他流水线的代码，代码更加的简洁了

因为，流水线的工作流程都已经封装好了，那么在接下来的测试中，只需要直接调用就可以了

```java
AssemblyLine assemblyLine = new RadioAssemblyLine();
assemblyLine.product();

System.out.println();

assemblyLine = new ComputerAssemblyLine();
assemblyLine.product();
```

看一下输出结果

```
+------Start Product------+
Produce Shell
Product Radio Components and Antennas
Assembly Components
Test Products
Product Radio Components and Antennas
Product Packing
+------Finish Product------+

+------Start Product------+
Product Aluminum housing and Liquid Crystal Display
Product Components and keyboard
Assembly Components
Test Products
Product Components and keyboard
Pack and Mark the Apple trademark
+------Finish Product------+
```

## 总结

在上面的编码过程中，模板方法最明显的优势就是将不变的地方进行封装，扩展可变的部分，这样操作更有利于维护。

模板方法是一种十分常用的设计模式，如果你是一名 Android Developer ，那么你应该知道 AsyncTask 这个用于异步加载的工具，那么 AsyncTask 就是一个在 Android 中一个模板方法的使用案例，当然不只有 AsyncTask，Android 的生命周期函数也使用了模板方法这个设计模式，有兴趣的同学可以去查看一下源码。

END.

[源码地址](https://github.com/InnoFang/DesignPatterns/tree/master/src/io/innofang/template_method)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://innofang.gitbook.io/oh-my-design-patterns/gitbook/hang-wei-xing-behavioral/1.-mo-ban-fang-fa-mo-shi.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
