模板方法模式

前言

模板方法模式是行为型设计模式,原理和代码实现都比较简单。算法

目录

1、定义

定义一个操做中的算法的框架,而将一些步骤延迟到子类中,使得子类能够不改变一个算法的结构便可重定义该算法的某些特定步骤。设计模式

一个父类下面的子类经过继承父类而使用通用的逻辑,同时根据各自须要优化其中某些步骤一个父类下面的子类经过继承父类而使用通用的逻辑,同时根据各自须要优化其中某些步骤服务器

2、模式原理分析

举个拉钩教育上的例子,设计一个简单的持续集成发布系统,研发部开发的代码放在GitLab上,并使用一个固定的发布流程来进行程序的上线发布。markdown

public abstract class DeployFlow {

    //使用final关键字来约束步骤不能轻易修改

    public final void buildFlow() {
        pullCodeFromGitlab(); //从GitLab上拉取代码
        compileAndPackage();  //编译打包
        copyToTestServer();   //部署测试环境
        testing();            //测试
        copyToRemoteServer(); //上传包到线上环境
        startApp();           //启动程序

    }

    public abstract void pullCodeFromGitlab();

    public abstract void compileAndPackage();

    public abstract void copyToTestServer();

    public abstract void testing();

    private void copyToRemoteServer() {
        System.out.println("统一自动上传 启动App包到对应线上服务器");
    }

    private void startApp() {
        System.out.println("统一自动 启动线上App");
    }

}
复制代码

分别实现两个子类:一、实现本地的打包编译和上传;二、实现全自动化的持续集成式的发布框架

public class LocalDeployFlow extends DeployFlow{

    @Override
    public void pullCodeFromGitlab() {
        System.out.println("手动将代码拉取到本地电脑......");
    }

    @Override

    public void compileAndPackage() {
        System.out.println("在本地电脑上手动执行编译打包......");
    }

    @Override
    public void copyToTestServer() {
        System.out.println("手动经过 SSH 上传包到本地的测试服务......");
    }

    @Override
    public void testing() {
        System.out.println("执行手工测试......");
    }

}

public class CicdDeployFlow extends DeployFlow{

    @Override
    public void pullCodeFromGitlab() {
        System.out.println("持续集成服务器将代码拉取到节点服务器上......");
    }

    @Override
    public void compileAndPackage() {
        System.out.println("自动进行编译&打包......");
    }

    @Override
    public void copyToTestServer() {
        System.out.println("自动将包拷贝到测试环境服务器......");
    }

    @Override
    public void testing() {
        System.out.println("执行自动化测试......");
    }
}
复制代码

运行一个单元测试ide

public class Client {

    public static void main(String[] args) {
        System.out.println("开始本地手动发布流程======");
        DeployFlow localDeployFlow = new LocalDeployFlow();
        localDeployFlow.buildFlow();
        System.out.println("********************");
        System.out.println("开始 CICD 发布流程======");
        DeployFlow cicdDeployFlow = new CicdDeployFlow();

        cicdDeployFlow.buildFlow();
    }
}

//输出结果
开始本地 手动发布流程======
手动将代码拉取到本地电脑......
在本地电脑上手动执行 编译打包......
手动经过 SSH 上传包 到 本地的测试服务......
执行手工测试......
统一自动上传 启动App包到对应线上服务器
统一自动 启动线上App
********************
开始 CICD 发布流程======
持续集成服务器将代码拉取到节点服务器上......
自动进行编译&打包......
自动将包拷贝到测试环境服务器......
执行 自动化 测试......
统一自动上传 启动App包到对应线上服务器
统一自动 启动线上App
复制代码

从上面场景的分析中,咱们能看出,模板方法模式应用场景的最大特征在于,一般是对算法的特定步骤进行优化,而不是对整个算法进行修改。一旦总体的算法框架被定义完成,子类便没法进行直接修改,由于子类的使用场景直接受到了父类场景的影响函数

3、使用场景

  • 多个子类有公有的方法,而且逻辑基本相同时
  • 重要、复杂的算法,能够把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现
  • 重构时,模板方法是一个常常使用的模式,把相同代码抽取到父类中,而后经过"钩子函数"约束其行为

4、优势

  • 有效去除重复代码
  • 封装不变部分,扩展可变部分
  • 提取公共部分代码,便于维护
  • 行为由父类控制,子类实现

5、缺点

  • 不符合开闭原则。 一个父类调用子类实现操做,经过子类扩展增长新的行为,可是子类执行的结果便会受到父类的影响,不符合开闭原则的“对修改关闭”。单元测试

  • 增长代码阅读的难度。 因为父类的某些步骤或方法被延迟到子类执行,那么须要跳转不一样的子类阅读代码逻辑,若是子类的数量不少的话,跳转会不少,不方便联系上下文逻辑线索。测试

  • 违反里氏替换原则。 虽然模板方法模式中的父类会提供通用的实现方法,可是延迟到子类的操做便会变成某种定制化的操做,一旦替换子类,可能会致使父类不可用或总体逻辑发生变化。优化

相关文章
相关标签/搜索