一 引入
豆浆制作有固定的步骤:选材–》添加配料–》浸泡–》放到豆浆机打碎
除了添加配料在不同口味豆浆中的操作不一样外,其他步骤在每次制作过程中都是一样的
这里就可以通过我们的模板方法实现
模板方法模式(Template Method Pattern),又叫模板模式(Template Pattern),在一个抽象类公开定义了执行它的方法的模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。
二 模板方法类图
- AbstractClass 抽象类, 类中实现了模板方法(template),定义了算法的骨架,具体子类需要去实现 其它的抽象方法operationr2,3,4
- ConcreteClass 实现抽象方法operationr2,3,4, 以完成算法中特点子类的步骤
三 代码实现
定义模板抽象类
public abstract class SoyaMilk {
/**
* 制备豆浆 通过final修饰防止子类覆写
*/
public final void make(){
selectSoya();
addCondiments();
soak();
beat();
}
/**
* 选择材料
*/
public void selectSoya(){
System.out.println("选择大豆");
}
/**
* 加入材料 交由子类实现
*/
public abstract void addCondiments();
/**
* 浸泡原料
*/
public void soak(){
System.out.println("浸泡原料");
}
/**
* 打碎原料
*/
public void beat(){
System.out.println("打碎原料");
}
}
定义抽象模板实现
public class PeanutSoyaMilk extends SoyaMilk{
@Override
public void addCondiments() {
System.out.println("添加美味的花生酱。。。");
}
}
public class SugarSoyaMilk extends SoyaMilk{
@Override
public void addCondiments() {
System.out.println("添加美味的糖果...");
}
}
客户端调用
public class Client {
public static void main(String[] args) {
System.out.println("制备糖果豆浆");
SoyaMilk sugarSoyaMilk = new SugarSoyaMilk();
sugarSoyaMilk.make();
System.out.println("制备花生豆浆");
SoyaMilk peanutSoyaMilk = new PeanutSoyaMilk();
peanutSoyaMilk.make();
}
}
运行结果:
制备糖果豆浆
选择大豆
添加美味的糖果...
浸泡原料
打碎原料
制备花生豆浆
选择大豆
添加美味的花生酱。。。
浸泡原料
打碎原料
四 模板方法模式的钩子方法
在模板方法模式的父类中,我们可以定义一个方法,它默认不做任何事,子类可以视情况要不要覆盖它,该方法称为“钩子”。
package com.yxj.template.improve;
//抽象类,表示豆浆
public abstract class SoyaMilk {
//模板方法, make , 模板方法可以做成final , 不让子类去覆盖.
final void make() {
select();
if(customerWantCondiments()) {
addCondiments();
}
soak();
beat();
}
//选材料
void select() {
System.out.println("第一步:选择好的新鲜黄豆 ");
}
//添加不同的配料, 抽象方法, 子类具体实现
abstract void addCondiments();
//浸泡
void soak() {
System.out.println("第三步, 黄豆和配料开始浸泡, 需要3小时 ");
}
void beat() {
System.out.println("第四步:黄豆和配料放到豆浆机去打碎 ");
}
//钩子方法,决定是否需要添加配料
boolean customerWantCondiments() {
return true;
}
}
package com.yxj.template.improve;
public class PeanutSoyaMilk extends SoyaMilk {
@Override
void addCondiments() {
// TODO Auto-generated method stub
System.out.println(" 加入上好的花生 ");
}
}
package com.yxj.template.improve;
public class RedBeanSoyaMilk extends SoyaMilk {
@Override
void addCondiments() {
// TODO Auto-generated method stub
System.out.println(" 加入上好的红豆 ");
}
}
package com.yxj.template.improve;
public class PureSoyaMilk extends SoyaMilk{
@Override
void addCondiments() {
// TODO Auto-generated method stub
//空实现
}
@Override
boolean customerWantCondiments() {
// TODO Auto-generated method stub
return false;
}
}
package com.yxj.template.improve;
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
//制作红豆豆浆
System.out.println("----制作红豆豆浆----");
SoyaMilk redBeanSoyaMilk = new RedBeanSoyaMilk();
redBeanSoyaMilk.make();
System.out.println("----制作花生豆浆----");
SoyaMilk peanutSoyaMilk = new PeanutSoyaMilk();
peanutSoyaMilk.make();
System.out.println("----制作纯豆浆----");
SoyaMilk pureSoyaMilk = new PureSoyaMilk();
pureSoyaMilk.make();
}
}
五 总结
优点:
1.可以提取公共的代码(选材,浸泡)这种公共的都是通过父类来定义而子类只需要继承。
2.同时扩展性强,需要整个更改流程的时候只需要更改模板,同时父类只需要定义顺序,子类来实现具体的内容。
缺点:
1.子类在做继承的时候必须要注意父类的具体顺序
2.如果模板中需要插入新的步骤,此时所有子类都需要进行实现(即使某些子类并不需要)