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

概述

通俗点讲,模板方法模式就是在一个模板方法中,按既定顺序执行一组步骤(方法),并将部分步骤(抽象方法)延迟到子类实现。

该模式把抽象父类设计为一个模板,所有子类都必须按照模板设定的骨架去按顺序执行方法。抽象类负责实现骨架中的公用方法(通用),子类负责实现必须改变的抽象方法(细节)。

作用

所有继承了抽象类的子类都会按照父类骨架编码。通用方法由父类实现,减少代码冗余。

应用场景

把定制系统项目开发很粗暴地看为一下流程:
需求定制 —— 系统框架设计 —— 业务结构设计 —— 编码 ——测试。

场景分析:不知道是不是所有定制开发都是这样的流程的,反正我这的新项目就是在从旧项目copy一份,然后按照新的业务需求来改!(ps:业务需求大致相近)。这样可以减少大量的开发成本

现在把项目看作一个抽象类。各个环节(步骤)是一个个的方法。现在需要分析哪些步骤是所有项目都相同的,把相同实现的抽取成公用方法。不同的为抽象方法,由各个具体项目子类实现。

需求定制(requireDesign):变动。不解释。

系统框架(systemFrame):不变动。所有项目统一框架很省钱!!!

业务结构设计(vocationDesign):可能变动。有些项目变动,有些直接搬。

编码(code):变动。每个项目都必定会改业务逻辑。

测试(test):不变动。就几个内部人员用的系统,大概只有功能测试。

场景分析

systemFrame()、test()所有项目是通用的,由父类统一实现
requireDesign()、code()所有项目都要重新实现,所以交由子类实现。

说到这里可能会疑惑:vocationDesign()方法应该怎样处理? 这里,交由父类实现一般的通用方法,原因是后面可以由“钩子”判断是否需要调用,钩子 放在下面作解释。

类图

这里写图片描述

代码

//项目基础抽象类
public abstract class Project {

    //由各个子类项目负责实现
    abstract public void requireDesign();
    abstract public void code();

    final public void systemFrame() {
        System.out.println("通用系统框架...");
    }

    final public void vocationDesign() {
        System.out.println("通用业务设计...");
    }

    final public void test() {
        System.out.println("通用测试方式...");
    }

    //定义一个模板方法,限定所有步骤的顺序
    final public void execute() {
        this.requireDesign();
        this.systemFrame();
        this.vocationDesign();
        this.code();
        this.test();
    }
}
//定制化的N个项目之一
public class AppleProject extends Project {

    @Override
    public void requireDesign() {
        System.out.println("我是Apple项目,我有不同的业务需求");
    }

    @Override
    public void code() {
        System.out.println("每次code都不一样,我是apple");
    }
}

//Main方法
public static void main(String[] args) {
        Project project = new AppleProject();
        project.execute();
}

输出
这里写图片描述

钩子

不知道大家看到这个模式时,有没联想到Java实例化对象的基础方法执行顺序。
创建:执行构造方法;
回收:执行finalize方法;

还有刚学Java Web时,继承了HttpServlet后,除了service()编码外,还可以在初始化init(),销毁destroy()中编码。

在开始分析时,vocationDesign方法是应该要按照实际情况灵活变化的。
上面代码明显不符合要求,模板应该设计得更灵活一些。

这时就应该使用“钩子”。

引用《Head First》原话:

钩子是一种被声明在抽象类中的方法,但只有空得或者默认的实现。
钩子的存在可以让子类有能力对算法的不同点进行挂钩。
要不要挂钩,由子类自行决定。

钩子有下面几种用法:

1.空方法: 在模板步骤的前后加入空方法,由子类自由选择是否需要覆写。

2.用作条件判断:在父类的步骤上加入if条件判断(钩子返回true/false),子类可以选择覆写钩子,跳过某些“不必要”的步骤。

旧模板与新模板对比:

这里写图片描述

修改后的代码

public abstract class Project {

    //由各个子类项目负责实现
    abstract public void requireDesign();
    abstract public void code();

    //钩子
    public void init() {}

    final public void systemFrame() {
        System.out.println("通用系统框架...");
    }

    final public void vocationDesign() {
        System.out.println("通用业务设计...");
    }

    final public void test() {
        System.out.println("通用测试方式...");
    }

    //空钩子
    public void destroy() {}

    //用作判断的钩子,默认返回true
    public boolean isChange() {
        return true;
    }

    //空钩子
    public void customDesgin() {}

    //定义一个模板方法,限定所有步骤的顺序
    final public void execute() {
        this.init();//空钩子
        this.requireDesign();
        this.systemFrame();
        if(isChange()) {
            this.vocationDesign(); //默认使用通用方法
        }else {
            this.customDesgin();  //由子类覆写
        }
        this.code();
        this.test();
        this.destroy(); //空钩子
    }
}
public class AppleProject extends Project {

    @Override 
    public void init() {
        System.out.println("这是一个可有可无的初始化方法init()");
    }

    @Override
    public boolean isChange() {
        System.out.println("在这里判断执行通用方法还是自定义方法!!!");
        return false;
    }

    @Override
    public void requireDesign() {
        System.out.println("我是Apple需求人员,我负责写不同的业务需求");
    }

    @Override
    public void code() {
        System.out.println("每次code都不一样,我是apple");
    }

    @Override
    public void customDesgin() {
        System.out.println("放弃原业务设计,自定义新的");
    }

    @Override
    public void destroy() {
        System.out.println("这是一个可有可无的销毁方法destroy()");
    }
}

输出结果

这里写图片描述

使用钩子的好处很明显

就是可以使模板在不影响主流程的情况下,尽量把系统设计得更加灵活。

由子类自己按照实际需求来选择要不要扩展部分功能。

总结

1.最基础的系统。模板类实现了系统的基本功能,属于“(框架)”,引用一句古语就是“麻雀虽小,五脏俱全”。

2.代码复用。子类可以使用模板的基础功能,也可以用钩子扩展部分功能。

3.保证系统稳定。所有子类都必须按照模板的骨架去设计。

最后,引用《Head First》的要点

1.“模板方法”定义了算法的步骤,把这些步骤的实际延迟到子类。

2.模板方法模式为我们提供了一种代码复用的重要技巧。

3.模板方法的抽象类可以定义具体方法、抽象方法和钩子。

4.抽象方法由子类实现。

5.钩子是一种方法,它在抽象类中不做事,或者只做默认的事情,子类可以选择要不要去覆盖它。

6.为了防止子类改变模板方法中的算法,可以将模板方法声明为final。

7.策略模式和模板方法模式都封装算法,一个用组合,一个用继承。

8.工厂方法是模板方法的一种特殊版本。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值