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

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

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原则,当一个子类中的方法有修改操作,不会影响其它子类对应的场景。在可读性方面,模板方法模式具备天然的易于理解的优势。之后遇到可能出现大量重复代码的时候,考虑模板方法设计模式。

相关推荐
李广坤11 小时前
状态模式(State Pattern)
设计模式
李广坤12 小时前
观察者模式(Observer Pattern)
设计模式
李广坤13 小时前
中介者模式(Mediator Pattern)
设计模式
李广坤13 小时前
迭代器模式(Iterator Pattern)
设计模式
李广坤14 小时前
解释器模式(Interpreter Pattern)
设计模式
阿无,17 小时前
java23种设计模式之前言
设计模式
Asort18 小时前
JavaScript设计模式(八):组合模式(Composite)——构建灵活可扩展的树形对象结构
前端·javascript·设计模式
数据智能老司机18 小时前
数据工程设计模式——数据基础
大数据·设计模式·架构
笨手笨脚の20 小时前
设计模式-代理模式
设计模式·代理模式·aop·动态代理·结构型设计模式
Overboom1 天前
[C++] --- 常用设计模式
开发语言·c++·设计模式