【实战一】模板方法模式
模板方法模式:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
抽象类
定义一个抽象类:FarmWorkNodeRecord
:表示其记录是用来操作计划的节点对象的。
public abstract class FarmWorkNodeRecordService {
// 模拟Mapper
private String plantPlanRuleDifferenceThresholdService = "plantPlanRuleDifferenceThresholdService";
private String plantPlanRuleInfoService = "plantPlanRuleInfoService";
private String plantPlanInfoService = "plantPlanInfoService";
/**
* 模板方法
*/
final void insertFarmWorkNodeRecordVo(String type){
// 1. 插入当前记录
insertFarmWorkNodeRecord();
// 2. 插入土地
insertBatchLand();
// 3. 更新种植计划规则
updatePlantPlanRule();
// 4. 更新规则差值表
calculatePlantPlanRuleDifferenceThreshold(type);
// 5. 计划节点操作状态更新
updateIfAccomplishNodeFarming(type);
}
/**
* 插入当前记录
*/
abstract void insertFarmWorkNodeRecord();
/**
* 插入土地
*/
abstract void insertBatchLand();
/**
* 仅延迟种植计划当前的节点规则
*/
void updateSelf(){
System.out.println("3. "+ plantPlanRuleInfoService +"\t仅延迟种植计划当前的节点规则");
}
/**
* 延迟种植计划当前节点以及后序的节点规则
*/
void updateSelfAndChild(){
System.out.println("3. "+ plantPlanInfoService +"\t延迟种植计划当前节点以及后序的节点规则");
}
/**
* 更新规则差值表
*/
void calculatePlantPlanRuleDifferenceThreshold(String nodeType){
System.out.println("4. " + plantPlanRuleDifferenceThresholdService +"\t【" + nodeType + "】更新规则差值表");
}
/**
* 计划节点操作状态更新: 父、 子
*/
void updateIfAccomplishNodeFarming(String nodeType){
System.out.println("5. " + plantPlanRuleInfoService +"\t【" + nodeType + "】更新节点操作状态");
}
/**
* 是否种植计划只延迟当前的结点规则
* @return true更新当前; false 延迟当前以及
*/
boolean isOnlyUpdateSelf() {
return true;
}
/**
* 更新种植计划规则
*
* <p>updateSelfAndChild
* <ul>
* <li> 延迟种植计划当前节点以及后序的节点规则:
*</ul>
* <p>updateSelf
* <ul>
* <li> 仅延迟种植计划当前的节点规则
*</ul>
*
*/
final void updatePlantPlanRule(){
if (isOnlyUpdateSelf()){
updateSelf();
}else {
updateSelfAndChild();
}
}
}
下面解释一下,对这个抽象类类进行优化的思想:
「首先,先对业务操作高度抽象化,转化为模板方法」
我们先把 上图 「待优化的代码 - 模板方法模式」框住的代码高度抽象化,变为步骤3
「接下来,对模板方法的步骤进行分析」
- 重复的代码,放到超类里面,统一进行管理
- 普通方法
- final 方法
- 不重复的代码,交给子类进行重写
- 抽象方法
「最后,通过钩子函数来决定到底调用哪个方法」
通过钩子函数:isOnlyUpdateSelf
来决定 步骤3updatePlantPlanRule
实际调用:updateSelf
或者 updateSelfAndChild
子类
子类BootStage实现:
public class FarmWorkNodeRecordBootStageServiceImpl extends FarmWorkNodeRecordService{
// 模拟Mapper
private String farmWorkRecordBootStageMapper = "farmWorkRecordBootStageMapper";
private String farmWorkRecordBootStageLandMapper = "farmWorkRecordBootStageLandMapper";
@Override
void insertFarmWorkNodeRecord() {
System.out.println("1. "+ farmWorkRecordBootStageMapper +"\t插入当前记录");
}
@Override
void insertBatchLand() {
System.out.println("2. "+ farmWorkRecordBootStageLandMapper +"\t插入土地");
}
}
子类SprayStage实现:
public class FarmWorkNodeRecordSprayStageServiceImpl extends FarmWorkNodeRecordService{
// 模拟代替Mapper
private String farmWorkSprayStageMapper = "farmWorkSprayStageMapper";
private String farmWorkRecordSprayStageLandMapper = "farmWorkRecordSprayStageLandMapper";
@Override
void insertFarmWorkNodeRecord() {
System.out.println("1. "+ farmWorkSprayStageMapper +"\t插入当前记录");
}
@Override
void insertBatchLand() {
System.out.println("2. "+ farmWorkRecordSprayStageLandMapper +"\t插入土地");
}
/**
* 重写钩子函数
* @return
*/
@Override
boolean isOnlyUpdateSelf() {
return false;
}
}
此时,对于模板方法也就完毕了。测试看看:
1. farmWorkRecordBootStageMapper 插入当前记录
2. farmWorkRecordBootStageLandMapper 插入土地
3. plantPlanRuleInfoService 仅延迟种植计划当前的节点规则
4. plantPlanRuleDifferenceThresholdService 【BootStage】更新规则差值表
5. plantPlanRuleInfoService 【BootStage】更新节点操作状态
1. farmWorkSprayStageMapper 插入当前记录
2. farmWorkRecordSprayStageLandMapper 插入土地
3. plantPlanInfoService 延迟种植计划当前节点以及后序的节点规则
4. plantPlanRuleDifferenceThresholdService 【SprayStage】更新规则差值表
5. plantPlanRuleInfoService 【SprayStage】更新节点操作状态
❓但是,此时我们还没有解决我们在前面框住的代码。我们还需要解决如下的场景:
我是觉得简易工厂模式比较符合。
目前还没有想好说服自己到底用哪一个。
咕咕咕。另外我还剩下两个模式没有看完。忙得很啊。
ok,我最后采用的是策略模式 (2024年4月7日15:12:36)
【实战二】策略模式
使用策略模式消除冗长的if-else|记一次smart-auto重构总结
策略模式: 封装可互换的行为,然后使用委托来决定要采用哪一个行为
在上一步的时候,我们还没有实现解决如下场景:
我打算采用的是行为型模式中的 「策略模式」 ,主要考虑到这一部分主要是涉及到类和对象如何去交互以及分配职责的。
策略模式是出现次数最多的“劳模”了,就是定义一个 「抽象类」 ,加入 UpdateRule,声明为 「接口类型的实例变量」 , 这样每个对象都会在运行的时候动态的引用正确的行为 。
- 开始进行对
FarmWorkNodeRecordService
的方法updatePlantPlanRule
进行修改,变为updatePlantPlanRuleNew
:
(updatePlantPlanRule
相关的方法已废弃)
- 新增实例变量
UpdateRule
,声明为接口类型 - 让实例变量能够进行动态修改
setUpdateRule(UpdateRule updateRule)
- 具体的实现规则交由子类具体实现
updatePlantPlanRuleNew(String type)
- 为了避免
UpdateRule
实例变量出现空指针异常的情况,重写了构造方法,默认了子类实现
public abstract class FarmWorkNodeRecordService {
/**
* todo 实例变量:用来指定如何更新种植计划规则
*/
private UpdateRule updateRule;
/**
* 构造方法,实例变量默认交给 UpdateSelf (更新种植计划规则: 延迟种植计划当前的节点规则 0 1 都操作)
*/
public FarmWorkNodeRecordService() {
this.updateRule = new UpdateSelf();
}
/**
* todo 对实例变化进行动态修改
* @param updateRule 更新种植计划规则接口
*/
public void setUpdateRule(UpdateRule updateRule){
this.updateRule = updateRule;
}
/**
* todo 更新种植计划规则,具体的实现规则交由子类具体实现
* @param type 节点类型
*/
public void updatePlantPlanRuleNew(String type){
updateRule.updateRule(type);
}
// do something
}
- 新增接口
UpdateRule
public interface UpdateRule {
/**
* 更新种植计划规则
* @param type 节点类型
*/
void updateRule(String type);
}
- 接口
UpdateRule
,不同的实现类实现接口中对updateRule
更新种植计划规则 的实现:
UpdateSelf
UpdateSelfByOne
UpdateSelfByZero
UpdateSelfAndChild
UpdateSelfAndChildByOne
UpdateSelfAndChildByZero
下面是对部分的举例:
public class UpdateSelfByOne implements UpdateRule {
// 模拟Mapper
private String plantPlanRuleInfoService = "plantPlanRuleInfoService";
@Override
public void updateRule(String type) {
System.out.println("3. 【"+ type + "】更新种植计划规则: 延迟种植计划当前的节点规则 1 操作");
System.out.println("(1) "+ plantPlanRuleInfoService +"\t仅延迟种植计划当前的节点规则:1 ");
}
}
public class UpdateSelfAndChild implements UpdateRule {
private String plantPlanInfoService = "plantPlanInfoService";
@Override
public void updateRule(String type) {
System.out.println("3. 【"+ type + "】延迟种植计划当前节点以及后序的节点规则: 0 1 都操作");
System.out.println("(1) "+ plantPlanInfoService +"\t延迟种植计划当前节点以及后序的节点规则: 0 ");
System.out.println("(2) "+ plantPlanInfoService +"\t延迟种植计划当前节点以及后序的节点规则: 1 ");
}
}
-
不需要对
FarmWorkNodeRecordBootStageServiceImpl
和FarmWorkNodeRecordSprayStageServiceImpl
进行修改 -
测试类
public class TestDrive {
public static void main(String[] args) {
FarmWorkNodeRecordService bootStage = new FarmWorkNodeRecordBootStageServiceImpl();
// 交给 子类UpdateSelfAndChild 实现具体的行为实现
bootStage.setUpdateRule(new UpdateSelfAndChild());
FarmWorkNodeRecordService sprayStage = new FarmWorkNodeRecordSprayStageServiceImpl();
// 交给 子类UpdateSelfByOne 实现具体的行为实现
sprayStage.setUpdateRule(new UpdateSelfByOne());
bootStage.insertFarmWorkNodeRecordVo("BootStage");
System.out.println();
sprayStage.insertFarmWorkNodeRecordVo("SprayStage");
}
}
- 查看输出结果
8. farmWorkRecordBootStageMapper 插入当前记录
9. farmWorkRecordBootStageLandMapper 插入土地
10. 【BootStage】延迟种植计划当前节点以及后序的节点规则: 0 1 都操作
(1) plantPlanInfoService 延迟种植计划当前节点以及后序的节点规则: 0
(2) plantPlanInfoService 延迟种植计划当前节点以及后序的节点规则: 1
11. plantPlanRuleDifferenceThresholdService 【BootStage】更新规则差值表
12. plantPlanRuleInfoService 【BootStage】更新节点操作状态
13. farmWorkSprayStageMapper 插入当前记录
14. farmWorkRecordSprayStageLandMapper 插入土地
15. 【SprayStage】更新种植计划规则: 延迟种植计划当前的节点规则 1 操作
(1) plantPlanRuleInfoService 仅延迟种植计划当前的节点规则:1
16. plantPlanRuleDifferenceThresholdService 【SprayStage】更新规则差值表
17. plantPlanRuleInfoService 【SprayStage】更新节点操作状态
补充一下完整的FarmWorkNodeRecordService
:其中,标注了 todo的 为本次补充或者修改的内容。
public abstract class FarmWorkNodeRecordService {
/**
* todo 实例变量:用来指定如何更新种植计划规则
*/
private UpdateRule updateRule;
// 模拟Mapper
private String plantPlanRuleDifferenceThresholdService = "plantPlanRuleDifferenceThresholdService";
private String plantPlanRuleInfoService = "plantPlanRuleInfoService";
private String plantPlanInfoService = "plantPlanInfoService";
/**
* todo 构造方法,对实例变量默认为 UpdateSelf (更新种植计划规则: 延迟种植计划当前的节点规则 0 1 都操作)
*/
public FarmWorkNodeRecordService() {
this.updateRule = new UpdateSelf();
}
/**
* todo 模板方法
*/
final void insertFarmWorkNodeRecordVo(String type){
// 1. 插入当前记录
insertFarmWorkNodeRecord();
// 2. 插入土地
insertBatchLand();
// 3. 更新种植计划规则 (更改)
updatePlantPlanRuleNew(type);
// 4. 更新规则差值表
calculatePlantPlanRuleDifferenceThreshold(type);
// 5. 计划节点操作状态更新
updateIfAccomplishNodeFarming(type);
}
/**
* 插入当前记录
*/
public abstract void insertFarmWorkNodeRecord();
/**
* 插入土地
*/
public abstract void insertBatchLand();
/**
* @deprecated todo 仅延迟种植计划当前的节点规则
*/
@Deprecated
void updateSelf(){
System.out.println("3. "+ plantPlanRuleInfoService +"\t仅延迟种植计划当前的节点规则");
}
/**
* @deprecated todo 延迟种植计划当前节点以及后序的节点规则
*/
@Deprecated
void updateSelfAndChild(){
System.out.println("3. "+ plantPlanInfoService +"\t延迟种植计划当前节点以及后序的节点规则");
}
/**
* 更新规则差值表
*/
void calculatePlantPlanRuleDifferenceThreshold(String nodeType){
System.out.println("4. " + plantPlanRuleDifferenceThresholdService +"\t【" + nodeType + "】更新规则差值表");
}
/**
* 计划节点操作状态更新: 父、 子
*/
void updateIfAccomplishNodeFarming(String nodeType){
System.out.println("5. " + plantPlanRuleInfoService +"\t【" + nodeType + "】更新节点操作状态");
}
/**
* @deprecated todo 是否种植计划只延迟当前的结点规则
* @return true更新当前; false 延迟当前以及
*/
@Deprecated
boolean isOnlyUpdateSelf() {
return true;
}
/**
*
* @deprecated todo 更新种植计划规则
*
* <p> Use {@link FarmWorkNodeRecordService#updatePlantPlanRuleNew(String type)} instead.
*
*
* <p>updateSelfAndChild
* <ul>
* <li> 延迟种植计划当前节点以及后序的节点规则:
*</ul>
* <p>updateSelf
* <ul>
* <li> 仅延迟种植计划当前的节点规则
*</ul>
*/
@Deprecated
final void updatePlantPlanRule(){
if (isOnlyUpdateSelf()){
updateSelf();
}else {
updateSelfAndChild();
}
}
/**
* todo 对实例变化进行动态修改
* @param updateRule 更新种植计划规则接口
*/
public void setUpdateRule(UpdateRule updateRule){
this.updateRule = updateRule;
}
/**
* todo 更新种植计划规则,委托给子类具体实现
* @param type 节点类型
*/
public void updatePlantPlanRuleNew(String type){
updateRule.updateRule(type);
}
}
- 我还想补充一个工厂方法模式的实战,看看有没有场景可以用到创建型的设计模式。
等我整理一下笔记。(2024年4月9日17:20:53——【设计模式】笔记篇)- 我目前写的还只是java版本的,看看后续再结合到Springboot 项目里面。
还有三个小任务点。
革命还未成功,继续咕咕咕~~~