责任链设计模式--在工作中的应用

617 阅读4分钟

责任链设计模式,简单来说就是使多个对象都有机会处理同一个请求,侧重于代码的可扩展性。 具体表现在对请求的处理进行解耦,责任链上的每一个对象都只处理自己的逻辑,体现了单一职责原则,同时也提高了代码的可扩展性,可以在责任链上新增新的处理对象。 责任链设计模式一般的使用场景有两种,一是责任链上的对象都要按顺序处理某个请求;二是责任链上的任一对象处理了请求,其它对象就不再处理。

1、背景:

公司主营港口无人驾驶,我负责云端,对接港口的自动化设备是工作内容的一部分。无人车在接收到作业指令后要去码头面(船舶停靠处)与岸桥(岸边桥式起重机,负责吊起集装箱)进行自动化交互,完成作业。岸桥自动化设备会周期性(一秒一次)通过MQTT协议向云端发送它的状态与数据,其中主要的数据有岸桥大车位置(岸桥离码头面原点的距离),引导无人车对位的步进距离(无人车要停在一个合适的位置岸桥才能正常作业,所以需要给一个引导值让无人车前进或后退进行对位)、抓箱的吊具尺寸(因为集装箱的尺寸有20尺、40尺、45尺,吊具就类似于抓娃娃机的那个爪子,所以吊具要根据集装箱尺寸进行尺寸变化才能抓住)以及一些状态数据。

目前主要的业务逻辑处理有四部分:

  • 根据岸桥大车位置计算岸桥的UTM坐标,保存起来留待云端地图展示。
  • 作业过程中,如果岸桥移动了且移动距离超过三米,重新给无人车下发指令,主要是将目的地改成移动后的位置
  • 根据自动化设备状态以及引导值完成给无人车的引导
  • 吊具尺寸变化要更新无人车的任务去重新对位

2、分析:

要针对岸桥自动化设备发来的数据做最起码四部分逻辑处理,还要有一些校验之类的处理,都写在一个类里显得这个类职责很不明确,且代码也会变多,不利于维护,之后再增加新的业务处理不仅使这个处理类进一步变臃肿,还可能会影响到其它部分。可维护性可扩展性都不好。结合责任链设计模式的特点来看,为每一个业务处理都单独定义一个类,使它们都去处理接收来的数据,每一块儿业务处理职责都很单一,利于维护,且将来增加新的业务逻辑,只需增加一个类即可。

为此定义一个抽象类AbstractQCHandler,以及四个子类:QCPositionSaveHandler,负责 保存岸桥坐标位置;QCPositionChangeHandler,负责岸桥位置变更的处理;QCAlignHandler,负责引导对位处理;QCSpreaderSizeChangeHandler,负责吊具尺寸变化处理。以及为实现链式调用,定义一个类QCHandlerChain,负责将各处理类进行调用。

3、代码:

3.1、抽象类 AbstractQCHandler:

@Slf4j
@Service
public abstract class AbstractQCHandler {
    // 对外提供的处理方法,因为我需要在每个子类处理业务之前先做一部分校验等工作
    //将真正的处理方法定义为抽象方法doHandle供各子类实现
    public void handle(ECSStatusDTO ecsStatusDTO) {
        // 省略部分校验以及前置处理工作
        /.../
        doHandle(ecsStatusDTO);
     
    }

    protected abstract void doHandle(ECSStatusDTO ecsStatusDTO);
    
}

3.2、岸桥位置保存处理类 QCPositionSaveHandler:

@Service("qcPositionSaveHandler")
public class QCPositionSaveHandler extends AbstractQCHandler {

    @Override
    public void doHandle(ECSStatusDTO ecsStatusDTO) {
        //省略具体处理
    }
    
}

3.3、岸桥位置变更处理类 QCPositionChangeHandler:

@Service("qcPositionChangeHandler")
@Slf4j
public class QCPositionChangeHandler extends AbstractQCHandler {

    @Override
    public void doHandle(ECSStatusDTO ecsStatusDTO) {
        // 省略具体处理
    }

}

3.4、岸桥对位处理类 QCAlignHandler:

@Service("qcAlignHandler")
public class QCAlignHandler extends AbstractQCHandler {

    @Override
    public void doHandle(ECSStatusDTO ecsStatusDTO) {
        // 省略具体处理
    }
    
}

3.5、岸桥吊具尺寸变化处理类 QCSpreaderSizeChangeHandler:

@Slf4j
@Service("qcSpreaderSizeChangeHandler")
public class QCSpreaderSizeChangeHandler extends AbstractQCHandler {

    @Override
    public void doHandle(ECSStatusDTO ecsStatusDTO) {
        // 省略具体处理
    }

}

3.6、链式调用类 QCHandlerChain:

@Service("qcHandlerChain")
public class QCHandlerChain {

    @Resource
    private List<AbstractQCHandler> qcHandlers;

    public void chain(ECSStatusDTO ecsStatusDTO) {
        for (AbstractQCHandler handler : qcHandlers) {
            handler.handle(ecsStatusDTO);
        }
    }
}

至此,只需要在消费MQTT消息的时候调用这个链式处理类的chain方法即可,将原本臃肿的代码分散开来。如下:

@Slf4j
@Component("qcMessageConsumerHandler")
public class ECSQCMessageConsumerHandler implements MessageHandler {

    @Resource(name = "qcHandlerChain")
    private QCHandlerChain qcHandlerChain;

    @Override
    public void handleMessage(Message<?> message) throws MessagingException {
        String topic = message.getHeaders().get(MqttHeaders.RECEIVED_TOPIC, String.class);
        Optional.of(message.getPayload())
                .map(payload -> JsonUtil.parseObject((String) payload, ECSStatusDTO.class))
                .ifPresent(ecsStatusDTO -> {
                    try {
                        qcHandlerChain.chain(ecsStatusDTO);
                    } catch (Exception e) {
                        log.error("处理QC消息失败,topic: {}, message: {}, error: {}", topic, message.getPayload(), ExceptionUtil.getSimpleStackTrace(e));
                    }
                });
    }
}

4、总结:

责任链设计模式侧重于扩展性,且由于责任链上的每一个对象的职责都很明确,所以也体现了单一职责原则,所带来的必然是良好的可维护性。之后遇到针对同一个请求,有很多业务处理的场景考虑使用责任链设计模式,好用!