模版方法模式--图文详解
- 采摘机器人-场景体验
- 模版方法模式-解决问题
- 模版方法模式-定义
- 优缺点
- 优点
- 缺点
采摘机器人-场景体验
今天看抖音上外国开始使用采摘苹果的机器人,我们模仿一下的他的大体流程:
- 主体采摘车进入苹果园
- 进入苹果指定采摘地点(路线)
- 采摘无人机起飞
- 识别苹果
- 识别苹果是否成熟
- 采摘并运送至采摘车储物空间
- 储物空间满时退出苹果园
- 到苹果储存地点卸载苹果
转化成代码:
public static void main(String[] args) {
String apple = "苹果";
String appleOrchard = "苹果园";
String mainBody = "主体采摘车";
String pickingDrone = "采摘无人机";
System.out.println("1:"+mainBody+"进入"+appleOrchard+"。");
System.out.println("2:"+mainBody+"进入"+apple+"指定采摘路径。");
System.out.println("3:"+pickingDrone+"起飞。");
System.out.println("4:"+pickingDrone+"通过"+apple+"识别算法,识别"+apple);
System.out.println("5:"+pickingDrone+"通过"+apple+"成熟度识别算法,识别成熟"+apple);
System.out.println("6:"+pickingDrone+"采摘成熟"+apple+"并送至"+mainBody+"储物空间。");
System.out.println("7:"+mainBody+"储物空间满时退出"+appleOrchard+"。");
System.out.println("8:"+mainBody+"到达"+apple+"储存仓库卸载"+apple);
}
执行结果:
农场主使用了上述机器人之后发现非常不错,所以选择桃子和🍐的采摘也要使用机器人进行。
于是桃子采摘的代码如下:
public static void main(String[] args) {
String peach = "桃子";
String peachOrchard = "桃子园";
String mainBody = "主体采摘车";
String pickingDrone = "采摘无人机";
System.out.println("1:"+mainBody+"进入"+peachOrchard+"。");
System.out.println("2:"+mainBody+"进入"+peach+"指定采摘路径。");
System.out.println("3:"+pickingDrone+"起飞。");
System.out.println("4:"+pickingDrone+"通过"+peach+"识别算法,识别"+peach);
System.out.println("5:"+pickingDrone+"通过"+peach+"成熟度识别算法,识别成熟"+peach);
System.out.println("6:"+pickingDrone+"采摘成熟"+peach+"并送至"+mainBody+"储物空间。");
System.out.println("7:"+mainBody+"储物空间满时退出"+peachOrchard+"。");
System.out.println("8:"+mainBody+"到达"+peach+"储存仓库卸载"+peach);
}
此时我们对比苹果和桃子采摘的代码会发现重复了是很高的。他们的处理过程基本相同。世间水果如此多,如果为每一种水果都按照这种方式写一个采摘机器人,那繁琐程度、无聊程度以及出现错误的概率是非常高的。
归纳一下上面代码的特点:有统一的处理流程,区别只是流程中某些步的具体实现可能不同。
模版方法模式-解决问题
为了解决上述问题,大佬们总结出了“模版方法模式”,也就是有一个方法它规定了某个事情的处理流程模版(规定某个地方要干什么事,具体怎么干不管),某些步骤的具体处理逻辑由子类去自己实现。
使用模版方法的思想改造我们的代码:
定义一个模版方法:
public abstract class FruitPick {
//用final修饰防止被子类重写
public final void pickWork(){
String mainBody = "主体采摘车";
String pickingDrone = "采摘无人机";
System.out.println("1:"+mainBody+"进入"+getOrchardName()+"。");
System.out.println("2:"+mainBody+"进入"+getFruitName()+"指定采摘路径。");
System.out.println("3:"+pickingDrone+"起飞。");
System.out.println("4:"+pickingDrone+"通过"+runIdentify(getFruitName()));
System.out.println("5:"+pickingDrone+"通过"+runMaturityIdentify(getFruitName()));
System.out.println("6:"+pickingDrone+"采摘成熟"+getFruitName()+"并送至"+mainBody+"储物空间。");
System.out.println("7:"+mainBody+"储物空间满时退出"+getOrchardName()+"。");
System.out.println("8:"+mainBody+"到达"+getFruitName()+"储存仓库卸载"+getFruitName());
}
/**
* 获取水果名称
* @return
*/
public abstract String getFruitName();
/**
* 获取水果园名称
* @return
*/
public abstract String getOrchardName();
/**
* 水果识别算法
* @param fruitName 水果名称
* @return
*/
public abstract String runIdentify(String fruitName);
/**
* 水果成熟度识别算法
* @param fruitName 水果名称
* @return
*/
public abstract String runMaturityIdentify(String fruitName);
}
模版方法中的苹果采摘类实现:
public class ApplePickMain extends FruitPick{
public static void main(String[] args) {
ApplePickMain applePickMain = new ApplePickMain();
applePickMain.pickWork();
}
@Override
public String getFruitName() {
return "苹果";
}
@Override
public String getOrchardName() {
return "苹果园";
}
@Override
public String runIdentify(String fruitName) {
//一系列苹果识别逻辑
if ("苹果".equals(fruitName)){
return "苹果识别算法识别完成,结果:是苹果";
}
return "苹果识别算法识别完成,结果:不是苹果";
}
@Override
public String runMaturityIdentify(String fruitName) {
//一系列苹果成熟度判断逻辑
return "苹果程度度识别算法识别完成,结果:已成熟。";
}
}
其他水果采摘类的实现方式同苹果类。
通过上述优化。重复的代码都被提升到了超类中,每一种水果对应的类只需要去完成自己独特的业务逻辑即可,而且公共的处理流程也被规范化。减少了出现问题的可能性。
模版方法模式-定义
模板方法模式(Template Method Pattern),又叫模板模式(Template Pattern),在一个抽象类公开定义了执行它的方法的模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。
简单说,模板方法模式,定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构,就可以重定义该算法的某些特定步骤,这种类型的设计模式属于行为型模式。
上述定义引自:模版方法模式
优缺点
优点
- 共同处理逻辑放在了父类,可以提高复用性。
- 个性化逻辑由子类自己去实现,提高代码的扩展性。
- 去除了子类的重复代码,符合开闭原则。
缺点
- 每中事物都要有一个子类实现,增加了类的数量。
- 如果父类增加新的抽象方法,所有子类都要修改。
- 间接增加了系统复杂性。