1、简介
概念:定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
实际上是封装了一个固定流程,该流程由几个步骤组成,具体步骤可以由子类进行不同实现,从而让固定的流程产生不同的结果。其实就是类的继承机制。
本质:抽象封装流程,具体进行实现
2、主要解决
当完成一个操作具有固定的流程时,由抽象固定流程步骤,具体步骤交给子类进行具体实现(固定的流程,不同的实现)。
3、优缺点
优点
- 封装不变,扩展可变:父类封装了具体流程以及实现部分不变行为,其它可变行为交由子类进行具体实现;
- 流程由父类控制,子类进行实现:框架流程由父类限定,子类无法更改;子类可以针对流程某些步骤进行具体实现;
缺点
- 抽象规定了行为,具体负责实现,与通常事物的行为相反,会带来理解上的困难(通俗地说,“父类调用了子类方法”);
4、使用场景
- 多个子类有公有的方法,并且逻辑基本相同时;
- 重要,复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现;
- 重构时,模板方法模式是一个经常使用的模式,把相同的代码抽取到父类,然后通过钩子函数约束其行为;
5、模式讲解
通用 UML 类图:
image主要包含两种角色:
- 抽象模板(AbstractClass):抽象模板类,定义了一套算法框架/流程;
- 具体实现(ConcreteClass):具体实现类,对算法框架/流程的某些步骤进行了实现;
以下是 模板方法模式 的通用代码:
class Client {
public static void main(String[] args) {
AbstractClass abc = new ConcreteClassA();
abc.templateMehthod();
abc = new ConcreteClassB();
abc.templateMehthod();
}
// 抽象模板类
static abstract class AbstractClass {
protected void step1() {
System.out.println("AbstractClass:step1");
}
protected void step2() {
System.out.println("AbstractClass:step2");
}
protected void step3() {
System.out.println("AbstractClass:step3");
}
// 声明为final方法,避免子类覆写
public final void templateMehthod() {
this.step1();
this.step2();
this.step3();
}
}
// 具体实现类A
static class ConcreteClassA extends AbstractClass {
@Override
protected void step1() {
System.out.println("ConcreateClassA:step1");
}
}
// 具体实现类B
static class ConcreteClassB extends AbstractClass {
@Override
protected void step2() {
System.out.println("ConcreateClassB:step2");
}
}
}
注:通常把抽象模板类AbstractClass
的模板方法templateMethod
定义成final
类型,避免子类对其覆写,并遵命定义算法结构/流程的语义。
举个例子
例子:程序员每天上班的干活过程。
分析:
开机-->写代码-->关机。整个流程是固定的,可以抽象出来定义一个流程;
其中,对于不同类型的程序员“写代码”这个步骤是不同的,java程序员写java代码,Php程序员写Php代码;开机和关机是完全相同的。
抽象一个父类定义这个流程:
public abstract class Work {
//定义算法步凑流程
public void workDay(){
//1上班开机
openComputer();
//2写代码
coding();
//3:下班关机
closeComputer();
}
//开机
private final void openComputer() {
System.out.println("到达公司,开机");
}
//写代码
protected abstract void coding();
//关机
private final void closeComputer() {
System.out.println("下班,关机");
}
}
具体实现
Java程序员:
public class JavaProgrammer extends Work {
@Override
protected void coding() {
System.out.println("Java程序员打开Idea,写Java代码。。。");
}
}
PHP程序员:
public class PhpProgrammer extends Work {
@Override
protected void coding() {
System.out.println("PHP程序员打开Zend Studio,写Php代码。。。");
}
}
使用
public class TemplateMethodDemo {
public static void main(String[] args) {
Work javaProgrammer = new JavaProgrammer();
javaProgrammer.workDay();
System.out.println("================");
Work phpProgrammer = new PhpProgrammer();
phpProgrammer.workDay();
}
}
结果如下:
到达公司,开机
Java程序员打开Idea,写Java代码。。。
下班,关机
================
到达公司,开机
PHP程序员打开Zend Studio,写Php代码。。。
下班,关机
6、模板模式在各源码中体现
(1)每天都在使用的HttpServlet里面的service方法,service方法里面定义了调用流程,根据客户端调用的不同方式,if else逻辑判断调用不同的方法,比如doGet,doPost,doDelete等实现restful调用,具体的doGet,doPost方法实现我们可以在我们自己定义的Servlet中进行重写。
(2)Mybatis框架中也有一些经典实用,比如BaseExecutor类,它是一个基础的SQL执行类,实现了大部分SQL的执行逻辑,然后把几个方法教给子类定制化完成,其中doUpdate(),doFlushStatements(),doQuery(),doQueryCursor()等方法都是由子类来实现的.
网友评论