【java_基础深入】模板方法设计模式的妙用 : 回调子类实现

模板方法设计模式应用场景

HttpServlet 的 service() 就是一个模板方法,它实现了Servlet规范,
DispatcherServlet 借助service() 的模板方法,拓展了自己的逻辑。
HttpServlet 是一个抽象类。抽象类是实现模板方法的基石,以下先举个简单例子,再从底层证明

实例

产品线定义:

/**
 * @Author james
 * @Description 鞋子产品线, 抽象类。该类实现了产品的规范
 * @Date 2019/12/23
 */
public abstract class ShoesProduct implements Product{

	// 默认是不上线
    private boolean available = false;

    public boolean isAvailable() {
        return available;
    }

    public void setAvailable(boolean available) {
        this.available = available;
    }

    /**
     * 默认留给子类实现,未实现,视为不支持功能,调用就抛异常
     *
     */
    protected void payOnline() {
        throw new RuntimeException("该产品未开通线上支付功能");
    }

    protected void sevenDay(){
        throw new RuntimeException("该产品不支持七天无理由退款");
    }

    /**
     * 鞋子产品线生成订单的模板方法
     *
     */
    @Override
    public void makeOrder() {
        if (isAvailable()) {
            payOnline();
            sevenDay();
        } else {
            throw new RuntimeException("该产品未上线,无法生成订单");
        }
    }
}

具体产品线实现

/**
 * @Author james
 * @Description 产品线的具体实现:Nike系列产品线
 * @Date 2019/12/23
 */
public class NikeShoesProduct extends ShoesProduct {
    // 产品名
    private String name;

    // 是否联名
    private boolean isJoint = false;

    @Override
    protected void payOnline() {
        System.out.println("支持支付宝付款");
    }

    /**
     * 联名发售, 自己拓展的业务功能
     */
    private void jointOffer() {
        System.out.println(name + " 联名Bape发售");
    }

    /**
     * 具体产品生成订单的实现
     */
    @Override
    public void makeOrder() {
        if (isJoint()) {
            jointOffer();
            super.makeOrder();
        } else {
            super.makeOrder();
        }
    }

    /**
     * 确定该产品是否上线, 为该产品命名
     *
     * @param isAvailable 是否上线
     */
    public NikeShoesProduct(boolean isAvailable, String name) {
        this.name = name;
        super.setAvailable(isAvailable);
    }

    public NikeShoesProduct(boolean isAvailable, boolean isJoint, String name) {
        this.name = name;
        this.isJoint = isJoint;
        super.setAvailable(isAvailable);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public boolean isJoint() {
        return isJoint;
    }

    public void setJoint(boolean joint) {
        isJoint = joint;
    }
}

模板方法的业务场景

		// nikeID 
        ShoesProduct nikeShoesProduct = new NikeShoesProduct(true, true, "nike ID 冬季系列");
        nikeShoesProduct .makeOrder(); // 生成该产品的订单信息

在这里插入图片描述
达到预期目的。这里的预期指的是:抽象类作为父类,可以通过抽象方法回调到子类的实现,这是一个很神奇的过程。可以观察如下的调用链

  1. 抽象类的子类实例nikeShoesProduct -> 调用本类的 makeOrder();
  2. nikeShoesProduct .makeOrder() -> 执行super.makeOrder() -> 调用抽象类ShoesProduct.makeOrder()
    以下抽象类的实现:
    /**
     * 默认留给子类实现,未实现,视为不支持功能,调用就抛异常
     *
     */
    protected void payOnline() {
        throw new RuntimeException("该产品未开通线上支付功能");
    }
    
    protected void sevenDay(){
        throw new RuntimeException("该产品不支持七天无理由退款");
    }
    
    /**
     * 生成订单
     *
     */
    @Override
    public void makeOrder(){
        if (isAvailable()) {
            payOnline();
            sevenDay();
        } else {
            throw new RuntimeException("该产品未上线,无法生成订单");
        }
    }
    
  3. 抽象类的makeOrder()-> 调用 payOnline()这是本文的关键点
    payOnline() 到底调用的是抽象类的 payOnline() 还是实现类的 payOnline()
    答案是:实现类的 payOnline()

分析

这本应该是个很基础的问题,之前写代码一直停留在看代码的程度,记死了this代表本类,super代表父类,这是不够准确的,只有在debug下才暴露了自己的问题。
其实在一个调用链上,this代表调用链起点的对象,实现类通过super访问了父类的方法,运行时,父类的this即是实现类

在这里插入图片描述
在这里插入图片描述

延伸

模板方法实现了父类调用子类的场景,而为什么采取继承抽象类而不是直接继承普通类

  1. 抽象类不能被实例化, this 的对象直接确定为实现类, 业务上提供单一的入口
    1.1 值得一提的是,抽象类中makeOrder() 中调用的payOnline()同样会在编译后变成this.payOnlin
  2. 抽象类同时参与适配器模式,abstract class HttpServlet extends GenericServlet 适配了GenericServlet,也让Servlet很好的支持Http协议, DispatcherServlet借力打力实现了Spring 的核心控制器。Spring中更典型的例子应该是 适配器模式、spring相关
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值