java设计模式——模板方法模式

一. 定义与类型

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

类型:行为型。

二. 使用场景

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

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

三. 优缺点

优点:

  (1)  提高复用性,将相同部分的代码,放入抽象父类中

  (2)  提高扩展性

  (3)  符合开闭原则

缺点:

  (1) 类数目增加

  (2) 增加了系统实现的复杂度

  (3) 继承关系自身缺点,如果父类添加新的抽象方法,所有子类都要改一遍

四. 模板方法—扩展

钩子方法

五. 相关设计模式

模板方法模式和工厂方法模式

  工厂方法是模板方法的一种特殊实现

模板方法模式和策略模式

  它们都有封装算法,策略模式的目的是使不同的算法可以相互替换,并且不影响应用层客户端的使用;而模板方法模式是针对一个定义算法的流程而将一些不太一样的,具体实现步骤交给子类来实现。模板方法是不改变算法的流程,而策略模式是可以改变的,有大量的if-else时,就可以考虑是否使用策略模式

六. Coding

模板方法模式其实非常简单,直接看下面的代码

/**
 * @program: designModel
 * @description:
 * @author: YuKai Fan
 * @create: 2019-02-13 14:50
 **/
public abstract class ACourse {
    //不希望子类覆盖这个方法,防止修改方法里面的录制课程流程的执行顺序
    protected final void makeCourse() {
        this.makePPT();
        this.makeVide0();
        if (needWriteArticle()) {
            this.writeArticle();
        }
        this.packageCourse();
    }

    final void makePPT() {
        System.out.println("制作PPT");
    }

    final void makeVide0() {
        System.out.println("制作视频");
    }

    final void writeArticle() {
        System.out.println("编写手记");
    }

    //钩子方法
    protected boolean needWriteArticle() {
        return false;
    }

    abstract void packageCourse();
}
/**
 * @program: designModel
 * @description:
 * @author: YuKai Fan
 * @create: 2019-02-13 14:55
 **/
public class DesignPatternCourse extends ACourse {
    void packageCourse() {
        System.out.println("提供课程java源代码");
    }

    @Override
    protected boolean needWriteArticle() {
        return true;
    }
}
/**
 * @program: designModel
 * @description:
 * @author: YuKai Fan
 * @create: 2019-02-13 14:56
 **/
public class FECourse extends ACourse {
    private boolean needWriteArticleFlag = false;
    void packageCourse() {
        System.out.println("提供课程的前端代码");
        System.out.println("提供课程的图片等多媒体素材等");
    }

    //这样的写法是为了满足不同的前端课程,可能jquery需要写手记,而html/css不需要写
    public FECourse(boolean needWriteArticleFlag) {
        this.needWriteArticleFlag = needWriteArticleFlag;
    }

    @Override
    protected boolean needWriteArticle() {
        return this.needWriteArticleFlag;
    }
}
/**
 * @program: designModel
 * @description:
 * @author: YuKai Fan
 * @create: 2019-02-13 14:57
 **/
public class Test {
    public static void main(String[] args) {
        System.out.println("后端设计模式课程start---");
        ACourse designPatternCourse = new DesignPatternCourse();
        //这里涉及到的钩子方法,其实是子类重写父类方法的一些基础规则,子类调用父类的方法,如果是被重写的,那调用的其实是子类重写过后的方法
        //也就是说,子类重写了父类的needWriteArticle()方法,在调用父类的makeCourse()时,调用了needWriteArticle()其实是子类重写的方法,也就是返回了true
        designPatternCourse.makeCourse();
        System.out.println("后端设计模式课程end---");

        System.out.println("前端课程start---");
        ACourse feCourse = new FECourse(false);
        feCourse.makeCourse();
        System.out.println("前端课程end---");

    }
}

具体的步骤注释都已经写在了代码中。

七. 源码分析

JDK中AbstractList,AbstractSet,AbstractMap类使用了模板方法模式

Servlet中的HttpServlet,doGet,doPost,service方法都是使用了模板方法

Mybatis中的BaseExecutor类也是采用了模板方法

原文地址:https://www.cnblogs.com/FanJava/p/10370096.html