004-行为型-02-模板方法模式(Template Method)

一、概述

  定义了一个算法的骨架,并允许子类为一个或多个步骤提供实现。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法的某些步骤

1.1、适用场景

  一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现

  各子类中公共的行为被提取出来并集中到一个公共父类中,从而避免代码重复

  一些方法通用,一些却在每一个子类都重新写了这一方法。

  Template Method模式一般应用在具有以下条件的应用中:

    1、具有统一的操作步骤或操作过程

    2、具有不同的操作细节

    3、存在多个具有同样操作步骤的应用场景,但某些具体的操作细节却各不相同

1.2、优缺点

优点:

  • 提高复用性,提取公共代码,便于维护
  • 提高扩展性
  • 符合开闭原则
  • 行为由父类控制,子类实现

缺点:

  • 类数目增加
  • 增加了系统实现的复杂度
  • 如果父类添加新的抽象方法,所有子类都要改一遍

注意:为防止恶意操作,一般模板方法都加上 final 关键词。

1.3、类图角色及其职责

  

  模板方法模式的角色和职责

  1、AbstractClass:抽象类的父类

  2、ConcreteClass:具体的实现子类

  3、templateMethod():模板方法,具体步骤方法的执行顺序(步骤)

  4、method1()与method2():具体步骤方法(细节)

1.4、演进过程

  代码来实现一下:我们举个例子,加入我们要组装汽车,步骤是,先组装车头,再组装车身,最后组装车尾,喷漆,是否需要打蜡

  这样,我们先建造AbstractClass(其中包含template模板,执行顺序)

// 组装车(AbstractClass)
public abstract class MakeCar {
    //定义结构里哪些方法是所有过程都是一样的可复用的,哪些是需要子类进行实现的
    //组装车头
    public abstract void makeCarHead();

    //组装车身
    public abstract void makeCarBody();

    //组装车尾
    public abstract void makeCarTail();

    //喷漆 都一样 统一实现
    public void makeCarPaint() {
        System.out.println("汽车喷漆");
    }

    //打蜡
    public abstract void makeCarDaLa();
    
    //声明一个钩子方法 需要打蜡 由用户确认 是否需要
    protected boolean needMakeCarDaLa() {
        return true;
    }

    //汽车组装流程(template()) 用来控制流程
    //申明为final,不希望子类覆盖这个方法,防止更改流程的执行顺序
    public final void makeCar() {
        this.makeCarHead();
        this.makeCarBody();
        this.makeCarTail();
        this.makeCarPaint();
        // 这里是否需要 交由钩子方法来决定
        if (needMakeCarDaLa()) {
            this.makeCarDaLa();
        }
    }
}

  再新建ConcreteClass(具体的实现细节)

//组装公交车
public class MakeBus extends MakeCar{

    @Override
    public void makeCarHead() {
        System.out.println("组装公交车车头");
    }

    @Override
    public void makeCarBody() {
        System.out.println("组装公交车车身");
    }

    @Override
    public void makeCarTail() {
        System.out.println("组装公交车车尾");
    }

    @Override
    public void makeCarDaLa() {

    }

    @Override
    protected boolean needMakeCarDaLa() {
        return false;
    }
}
//  组装SUV
public class MakeSuv extends MakeCar{

    @Override
    public void makeCarHead() {
        System.out.println("组装SUV车头");
    }

    @Override
    public void makeCarBody() {
        System.out.println("组装SUV车身");
    }

    @Override
    public void makeCarTail() {
        System.out.println("组装SUV车尾");
    }

    @Override
    public void makeCarDaLa() {
        System.out.println("组装SUV-打蜡");
    }
}

测试

    @Test
    public void makeCar() {
        MakeCar makeBus = new MakeBus();
        makeBus.makeCar();

        System.out.println("===========================");

        MakeCar makeSuv = new MakeSuv();
        makeSuv.makeCar();
    }

  用户不必关心具体的执行流程(步骤)

  输出

组装公交车车头
组装公交车车身
组装公交车车尾
汽车喷漆
===========================
组装SUV车头
组装SUV车身
组装SUV车尾
汽车喷漆
组装SUV-打蜡

二、扩展

  spring 中对 Hibernate 的支持,将一些已经定好的方法封装起来,比如开启事务、获取 Session、关闭 Session 等,程序员不重复写那些已经规范好的代码,直接丢一个实体就可以保存。

  jdk:java.util.AbstractList定义一套算法模板,如get(),set()等等,由子类实现。

  servlet:javax.servlet.http.HttpServlet定义一套算法模板,如doGet()、doPost()等等,由子类实现。。

  mybatis:org.apache.ibatis.executor.BaseExecutor

猜你喜欢

转载自www.cnblogs.com/bjlhx/p/11421119.html