设计模式---模板模式

本文围绕模板方法模式展开,先介绍其基本概念,即定义操作算法骨架,将部分步骤延迟到子类。接着以豆浆制作问题为例,展示如何用该模式解决。还提到了钩子方法,可让子类按需覆盖。最后说明了模板模式的优缺点及使用场景。

问题引出:豆浆制作问题
编写制作豆浆的程序,说明如下:制作豆浆的流程选材 ----> 添加配料 ----> 浸泡 ----> 放到豆浆机打碎,通过添加不同的配料,可以制作出不同口味的豆浆,选材、浸泡和放到豆浆机打碎这几个步骤对于制作每种口味的豆浆都是一样的
请使用模板方法模式完成

模板模式的基本介绍

模板方法模式(template method pattern),又叫模板模式(template pattern),在一个抽象类公开定义了执行他的方法的模板,它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行
简单来说,模板方法模式定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构,就可以重新定义该算法的某些特定步骤

原理类图
在这里插入图片描述
对原理类图的说明——即模板方法模式的角色和职责
AbstractClass抽象类中实现了模板方法,定义了算法的骨架,具体子类需要去实现其抽象方法或重写其中方法
ConcreteClass实现了抽象方法,已完成算法中特定子类的步骤

模板模式解决豆浆制作问题

在这里插入图片描述

/**
 * 抽象方法
 */
public abstract class SoyaMilk {
    /**
     * 模板方法,定义为final禁止覆写
     */
    public final void make() {
        System.out.println(">>>>>>豆浆制作开始<<<<<<");
        useSoyBean();
        addIngredients();
        soak();
        mash();
        System.out.println(">>>>>>豆浆制作结束<<<<<<");
    }

    protected void useSoyBean() {
        System.out.println("Step1. 选用上好的黄豆.");
    }

    protected abstract void addIngredients();

    protected void soak() {
        System.out.println("Step3. 对黄豆和配料进行水洗浸泡.");
    }

    protected void mash() {
        System.out.println("Step4. 将充分浸泡过的黄豆和配料放入豆浆机中,开始打豆浆.");
    }
}
/**
 * 花生豆浆
 */
public class PeanutSoyaMilk extends SoyaMilk {
    public PeanutSoyaMilk() {
        System.out.println("============花生豆浆============");
    }
    @Override
    protected void addIngredients() {
        System.out.println("Step2. 加入上好的花生.");
    }
}
/**
 * 红豆豆浆
 */
public class RedBeanSoyaMilk extends SoyaMilk {
    public RedBeanSoyaMilk() {
        System.out.println("============红豆豆浆============");
    }
    @Override
    protected void addIngredients() {
        System.out.println("Step2. 加入上好的红豆.");
    }
}
/**
 * 芝麻豆浆
 */
public class SesameSoyaMilk extends SoyaMilk {
        public SesameSoyaMilk() {
        System.out.println("============芝麻豆浆============");
    }
    @Override
    protected void addIngredients() {
        System.out.println("Step2. 加入上好的芝麻.");
    }
}
SoyaMilk peanutSoyaMilk = new PeanutSoyaMilk();
peanutSoyaMilk.make();
SoyaMilk redBeanSoyaMilk = new RedBeanSoyaMilk();
redBeanSoyaMilk.make();
SoyaMilk sesameSoyaMilk = new SesameSoyaMilk();
sesameSoyaMilk.make();
/*
============花生豆浆============
>>>>>>豆浆制作开始<<<<<<
Step1. 选用上好的黄豆.
Step2. 加入上好的花生.
Step3. 对黄豆和配料进行水洗浸泡.
Step4. 将充分浸泡过的黄豆和配料放入豆浆机中,开始打豆浆.
>>>>>>豆浆制作结束<<<<<<
============红豆豆浆============
>>>>>>豆浆制作开始<<<<<<
Step1. 选用上好的黄豆.
Step2. 加入上好的红豆.
Step3. 对黄豆和配料进行水洗浸泡.
Step4. 将充分浸泡过的黄豆和配料放入豆浆机中,开始打豆浆.
>>>>>>豆浆制作结束<<<<<<
============芝麻豆浆============
>>>>>>豆浆制作开始<<<<<<
Step1. 选用上好的黄豆.
Step2. 加入上好的芝麻.
Step3. 对黄豆和配料进行水洗浸泡.
Step4. 将充分浸泡过的黄豆和配料放入豆浆机中,开始打豆浆.
>>>>>>豆浆制作结束<<<<<<
*/

钩子方法

在模板方法模式的父类中。我们可以定义一个方法,默认它不做任何事情,子类可以视情况要不要覆盖他,该方法称之为钩子,
还是用上面做豆浆的例子来讲解,比如,我们还希望制作纯豆浆,不添加任何的配料,下面是使用钩子方法的改造,

public abstract class SoyaMilk {
    public final void make() {
        // ...
        if (customAddIngredients()) {
            addIngredients();
        }
        // ...
    }
    // ...
}

/**
 * 纯豆浆
 */
public class PureSoyaMilk extends SoyaMilk {
    public PureSoyaMilk() {
        System.out.println("============纯豆浆============");
    }

    @Override
    protected void addIngredients() {
        // 空实现即可
    }

    @Override
    protected Boolean customAddIngredients() {
        return false;
    }
}
SoyaMilk pureSoyaMilk = new PureSoyaMilk();
pureSoyaMilk.make();
/*
============纯豆浆============
>>>>>>豆浆制作开始<<<<<<
Step1. 选用上好的黄豆.
Step3. 对黄豆和配料进行水洗浸泡.
Step4. 将充分浸泡过的黄豆和配料放入豆浆机中,开始打豆浆.
>>>>>>豆浆制作结束<<<<<<
*/

注意事项和细节

基本思想:算法只存在于一个地方,也就是在父类中,容易修改。需要修改算法时,只要修改父类的模板方法或者已经实现的某些步骤,子类就会继承这些修改
实现了最大化代码复用。父类的模板方法和已实现的某些步骤会被子类继承而直接使用
既统一了算法,也提供了很大的灵活性。父类的模板方法确保了算法的结构保持不变,同时由子类提供部分步骤的实现
不足之处:每一个不同的实现都需要一个子类实现,导致类的个数增加,使得系统更加庞大
一般模板方法都加上final关键字,防止子类重写模板方法
使用场景:当要完成在某个过程,该过程要执行一系列步骤,这一系列的步骤基本相同,但其个别步骤在实现时可能不同,通常考虑用模板方法模式来处理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值