豆浆制作问题
编写制作豆浆的程序,说明如下:
- 1)制作豆浆的流程选材 ----> 添加配料 ----> 浸泡 ----> 放到豆浆机打碎
- 2)通过添加不同的配料,可以制作出不同口味的豆浆
- 3)选材、浸泡和放到豆浆机打碎这几个步骤对于制作每种口味的豆浆都是一样的
- 4)请使用模板方法模式完成
基本介绍
- 1)模板方法模式(Template Method Pattern),又叫模板模式(Template Pattern),在一个抽象类公开定义了执行它的方法的模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行
- 2)简单说,模板方法模式定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构,就可以重定义该算法的某些特定步骤
- 3)这种类型的设计模式属于行为型模式
原理类图
对原理类图的说明——即模板方法模式的角色和职责
- AbstractClass抽象类中实现了模板方法,定义了算法的骨架,具体子类需要去实现其抽象方法或重写其中方法
- ConcreteClass实现了抽象方法,已完成算法中特定子类的步骤
模板模式解决豆浆制作问题
核心代码
/**
* @ClassName SoyaMilk
* @author: shouanzh
* @Description SoyaMilk 抽象类 表示豆浆
* @date 2022/1/24 21:20
*/
public abstract class SoyaMilk {
// 模版方法 不让子类覆盖
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. 将充分浸泡过的黄豆和配料放入豆浆机中,开始打豆浆.");
}
}
/**
* @ClassName RedBeanSoyaMilk
* @author: shouanzh
* @Description RedBeanSoyaMilk
* @date 2022/1/24 21:31
*/
public class RedBeanSoyaMilk extends SoyaMilk{
public RedBeanSoyaMilk() {
System.out.println("============红豆豆浆============");
}
@Override
protected void addIngredients() {
System.out.println("Step2. 加入上好的红豆.");
}
}
/**
* @ClassName PeanutSoyaMilk
* @author: shouanzh
* @Description PeanutSoyaMilk
* @date 2022/1/24 21:32
*/
public class PeanutSoyaMilk extends SoyaMilk{
public PeanutSoyaMilk() {
System.out.println("============花生豆浆============");
}
@Override
protected void addIngredients() {
System.out.println("Step2. 加入上好的花生.");
}
}
/**
* @ClassName Client
* @author: shouanzh
* @Description Client
* @date 2022/1/24 21:33
*/
public class Client {
public static void main(String[] args) {
SoyaMilk redBeanSoyaMilk = new RedBeanSoyaMilk();
redBeanSoyaMilk.make();
SoyaMilk peanutSoyaMilk = new PeanutSoyaMilk();
peanutSoyaMilk.make();
}
}
钩子方法
- 1)在模板方法模式的父类中,我们可以定义一个方法,它默认不做任何事,子类可以视情况要不要覆盖它,该方法称为“钩子”
- 2)还是用上面做豆浆的例子来讲解,比如,我们还希望制作纯豆浆,不添加任何的配料,请使用钩子方法对前面的模板方法进行改造
核心代码
/**
* @ClassName SoyaMilk
* @author: shouanzh
* @Description SoyaMilk 抽象类 表示豆浆
* @date 2022/1/24 21:20
*/
public abstract class SoyaMilk {
// 模版方法 不让子类覆盖
public final void make() {
System.out.println(">>>>>>豆浆制作开始<<<<<<");
useSoyBean();
if (customerWantCondiments()) {
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. 将充分浸泡过的黄豆和配料放入豆浆机中,开始打豆浆.");
}
// 钩子方法
Boolean customerWantCondiments() {
return true;
}
}
/**
* @ClassName PureSoyaMilk
* @author: shouanzh
* @Description 纯豆浆
* @date 2022/1/24 21:47
*/
public class PureSoyaMilk extends SoyaMilk{
public PureSoyaMilk() {
System.out.println("-----纯豆浆-------");
}
// 空实现
@Override
protected void addIngredients() {
}
@Override
Boolean customerWantCondiments() {
return false;
}
}
/**
* @ClassName Client
* @author: shouanzh
* @Description Client
* @date 2022/1/24 21:33
*/
public class Client {
public static void main(String[] args) {
// 纯豆浆
SoyaMilk pureSoyaMilk = new PureSoyaMilk();
pureSoyaMilk.make();
// -----纯豆浆-------
// >>>>>>豆浆制作开始<<<<<<
// Step1. 选用上好的黄豆.
// Step3. 对黄豆和配料进行水洗浸泡.
// Step4. 将充分浸泡过的黄豆和配料放入豆浆机中,开始打豆浆.
// >>>>>>豆浆制作结束<<<<<<
}
}
注意事项和细节
- 1)基本思想:算法只存在于一个地方,也就是在父类中,容易修改。需要修改算法时,只要修改父类的模板方法或者已经实现的某些步骤,子类就会继承这些修改
- 2)实现了最大化代码复用。父类的模板方法和已实现的某些步骤会被子类继承而直接使用
- 3)既统一了算法,也提供了很大的灵活性。父类的模板方法确保了算法的结构保持不变,同时由子类提供部分步骤的实现
- 4)不足之处:每一个不同的实现都需要一个子类实现,导致类的个数增加,使得系统更加庞大
- 5)一般模板方法都加上final关键字,防止子类重写模板方法
- 6)使用场景:当要完成在某个过程,该过程要执行一系列步骤,这一系列的步骤基本相同,但其个别步骤在实现时可能不同,通常考虑用模板方法模式来处理