设计模式之模板方法设计模式--在工作中的实际应用

模板方法设计模式侧重于代码复用,只需要在父类中定义一套处理流程,将其中的不变部分封装起来,可变的部分交由子类去实现即可。可提升代码的可读性、可维护性、灵活性。

1、背景:

公司的主营业务是港口无人驾驶,我的工作内容是云端部分,工作内容之一就是对接港口的自动化设备厂商,完成自动化作业。

1.1、名词解释:

岸桥:岸边桥式起重机,将集装箱从船上吊起放在无人车上或者反着来

场桥:堆场桥式起重机,将集装箱从无人车上吊起放在堆场或者反着来

码头面:岸桥作业场地

堆场:港口存放集装箱的场地

吊具:岸桥、场桥设备用来吊集装箱的部分设施

1.2、流程:

无人车接到指令去码头面做卸船装箱任务,到指令中指定的岸桥下作业,与岸桥上安装的自动化作业设备进行交互,等待吊具将集装箱放在无人车上。无人车上装好箱子后接到去堆场做卸船卸箱任务,到指令中指定的场桥下作业,与场桥上安装的自动化作业设备进行交互,等待吊具将集装箱从无人车上吊走。

无人车与岸桥场桥的自动化交互流程是一样的,只是各自执行对应流程的条件以及时机不一样,所以此时适合固定一套作业流程的模板,主流程固定,至于岸桥场桥各自触发交互的条件按实际情况去实现。为此定义一个抽象类名为AbstractEcsDataHandler;岸桥流程处理子类定义为ECSQCDataHandler,继承该抽象类;场桥流程处理子类定义为ECSRMGDataHandler,继承该抽象类。

2、代码:

抽象类:AbstractEcsDataHandler:

java 复制代码
public abstract class AbstractEcsDataHandler {
    public void handle(ECSStatusDTO ecsStatusDTO) {
        Optional.of(mappingVehicleAndEquipment())// 获取无人车与岸桥场桥设备的绑定关系,一个岸桥或者场桥可能对应多个无人车,key是vehicleId,代表车号,value是equipmentId代表岸桥场桥设备编号
                .map(Map::entrySet)
                .orElseGet(Collections::emptySet)
                .stream()
                .filter(entry -> StringUtils.equals(ecsStatusDTO.getCraneCode(), entry.getValue()))
                .map(Map.Entry::getKey)
                .map(vehicleId -> redisManager.get(RedisKeyConstants.SN_API_TASK_CACHE_EXEC_TASK + vehicleId))// 获取无人车任务指令字符串
                .map(cachedExecTaskStr -> JsonUtil.parseObject(cachedExecTaskStr, TaskDto.class))// 反序列化出任务dto
                .filter(Objects::nonNull)
                .filter(this::isCorrectTaskType) // 任务中有是岸桥任务还是场桥任务属性,交由两个子类去实现
                .filter(cachedExecTask -> isCorrectWorkPosition(ecsStatusDTO, cachedExecTask))// 任务中有作业目的地,岸桥场桥对目的地的定义不一致,交由两个子类去实现
                .filter(cachedExecTask -> {
                    // 判断是否收到自动化设备的解锁指令,交由两个子类实现
                    if (isNotUnLockCommand(ecsStatusDTO)) {
                        return true;
                    }
                    // 省略收到自动化设备解锁方法
                    log.info("xxxxxxxxx");
                    return false;
                })
                .filter(cachedExecTask -> {
                    if(xxx) {
                        // 省略此部分方法
                        return true;
                    }
                    log.info("xxxxxxxxx");
                    return false;					
                })
                .findFirst()
                .filter(cachedExecTask -> isNotLocked(cachedExecTask.getTruckId()))
                .filter(cachedExecTask -> {
                    // 判断是否收到自动化设备的锁车指令,交由两个子类实现
                    if (isNotLockCommand(ecsStatusDTO)) {
                        return true;
                    }
                    // 省略收到自动化设备的锁车处理
                    return false;
                })
                .filter(cachedExecTask -> {
                    // 判断是否对位完成,交由两个子类实现
                    if (isNotAlignFinish(ecsStatusDTO)) {
                        return true;
                    }
                    // 省略对位完成处理
                    return false;
                })
                .filter(cachedExecTask -> {
                    // 判断无人车是否需要对位,交由两个子类实现
                    if (vehicleNeedAlign(ecsStatusDTO)) {
                        return true;
                    }
                    // 省略不需要对位的处理
                    return false;
                })
                .ifPresent(cachedExecTask -> {
                    // 获取自动化设备下发的对位值,交由两个子类实现
                    int currentDistance = acquireAlignDistance(ecsStatusDTO);
                    // 省略对位值的处理
                });
    }

    /**
     * 车辆和要作业的ECS设备的映射关系 key: vehicleId value: qcId or rmgId
     */
    protected abstract Map<String, String> mappingVehicleAndEquipment();

    protected abstract boolean isCorrectTaskType(TaskDto task);

    protected abstract boolean isCorrectWorkPosition(ECSStatusDTO ecsStatusDTO, TaskDto task);

    protected abstract boolean isNotUnLockCommand(ECSStatusDTO ecsStatusDTO);

    protected abstract boolean isNotLockCommand(ECSStatusDTO ecsStatusDTO);

    protected abstract boolean isNotAlignFinish(ECSStatusDTO ecsStatusDTO);

    protected abstract boolean vehicleNeedAlign(ECSStatusDTO ecsStatusDTO);

    protected abstract int acquireAlignDistance(ECSStatusDTO ecsStatusDTO);
	
}

两个子类ECSQCDataHandler和ECSRMGDataHandler特别干净,只需要实现父类中的抽象方法即可,调用时直接使用handle()方法处理。

3、总结:

模板方法设计模式在一些固定业务的场景中特别适合,极大的省去了重复代码的编写成本以及维护成本,符合OCP原则,当一个子类中的方法有修改操作,不会影响其它子类对应的场景。在可读性方面,模板方法模式具备天然的易于理解的优势。之后遇到可能出现大量重复代码的时候,考虑模板方法设计模式。

相关推荐
qq_297574671 天前
设计模式系列文章(基础篇第 11 篇):模板方法模式——定义算法骨架,实现代码复用与流程统一
算法·设计模式·模板方法模式
狂人开飞机1 天前
01. 工厂模式(Factory Pattern)
设计模式·c#
阿狸猿2 天前
论软件设计模式及其应用
设计模式
workflower2 天前
具身智能-三层结构
人工智能·设计模式·动态规划·软件工程·scrum
我爱cope2 天前
【Agent智能体10 | 反思设计模式-AI数据分析的可视化实战】
人工智能·设计模式·数据分析
老码观察2 天前
设计模式实战解读(七):适配器模式——让不兼容的接口无缝协作
java·设计模式·适配器模式
人月神话-Lee2 天前
【图像处理】框架设计——协议、值类型与工程化思维
图像处理·人工智能·ios·设计模式·架构·ai编程·swift
AI大法师2 天前
Xbox回归经典绿
大数据·设计模式·xbox
老码观察3 天前
设计模式实战解读(六):装饰器模式——功能增强,不动原代码
java·设计模式·装饰器模式