设计模式(策略、工厂、模板、责任链)的使用实例

业务背景

server与单片机交互使用私有16进制协议,其中某个字节代表该帧的命令类型(cmd_type)。

比如 0xaa 0xff 0x01........      0xaa 0xff 0x02.......    0xaa 0xff 0x03 ......

0x01表示上报心跳。 0x02表示上报时间。 0x03表示上报水温等

 

server需要针对不同的帧做不同的处理,然后给单片机对应的响应

 

原先代码结构是在一个类中使用 switch (cmd_type)   case 0x01. ..... ;  case 0x02 ....... case 0x03 .....

依赖错综复杂,代码臃肿混乱, 且每次添加新的命令都需要扩写该类添加其复杂性,不满足开闭原则。 

 

改写


首先抽象一个标志接口 MachineReportHandler

public interface MachineReportHandler {
    
    void handle(FrameResponse response, WHFrame frame);
}

然后基于处理器都是先处理然后响应的过程使用模板方法抽象  AbstractMachineReportHandler

public abstract class AbstractMachineReportHandler implements MachineReportHandler {
    
    @Override
    public void handle(FrameResponse response, WHFrame frame) {
        try {
            doHandleLogic(frame);
            
        } finally {
            
            doResponse(response, frame);
        }
    }

    protected abstract void doHandleLogic(WHFrame frame);

    protected abstract void doResponse(FrameResponse response, WHFrame frame);
}

具体某个命令的处理器继承AbstractMachineReportHandler重写doHandleLogic和doResponse方法即可,下面列出一个例子

@Component("HotMachineRequestHandler_cmd_01")
public class HotMachineRegHandler extends AbstractMachineReportHandler {
    
    private Logger logger = Logger.getLogger(HotMachineRegHandler.class);
    
    @Autowired
    MachineRegisterService machineRegisterService;
    
    @Autowired
    MachineMapper machineMapper;
    
    @Autowired
    MachineDao machineDao;
    
    @Autowired
    SimDao simDao;

    @Override
    protected void doHandleLogic(WHFrame frame) {
        logger.info("注册帧:" + frame.toString());
        
        //省略具体业务代码
    }

    @Override
    protected void doResponse(FrameResponse res, WHFrame frame) {
       //省略具体业务代码
    } 
}

注意这里给bean的命令,前缀统一,后缀使用对应被处理帧命令的具体值,方便工厂中根据帧内容获取对应的处理器

public class HotMachineReportHandlerFactory {
    
    private static Logger logger = Logger.getLogger(HotMachineReportHandlerFactory.class);

    private static final String BEAN_NAME_PREFIX = "HotMachineRequestHandler_cmd_";
    
    public static MachineReportHandler getHandler(byte cmd_type) {
        
        String bean_name_suffix = StringUtil.padLeft(Integer.toHexString(cmd_type & 0xff), 2, '0');
        
        String beanName = BEAN_NAME_PREFIX + bean_name_suffix;
        
        MachineReportHandler bean = null;try {
            bean = (MachineReportHandler) SpringContextUtil.getBean(beanName);
        } catch (BeansException err) {
            logger.error("未找到开水器上报命令类型为cmd_type: 0x" + bean_name_suffix + "对应的处理器");
            bean = null;
        }
        
        return bean;
    }
    
}

最后改写大块switch case语句

 

  MachineReportHandler bean = HotMachineReportHandlerFactory.getHandler(whFrame.getFrame_cmd());
  if (null != bean) {
        bean.handle(this, whFrame);
  }

 

 

后期刷卡打水命令需求变更, 刷卡打水命令需要根据设备的类型配置,采取不同的处理方式。  普通设备保持原业务逻辑, 加卡机将卡号入库,清卡机将卡号删除。

采用责任链模式扩展,设置好链中处理器的顺序,每个处理器先判断是否由自己处理,是则处理,否则交给下一个处理器

payload_res = AbstractReportCardnoHandler.getChain().prehandle(mac, cardno);

 

public  abstract class AbstractReportCardnoHandler implements ReportCardnoHandler {
    
    protected AbstractReportCardnoHandler nextHandler;
    
    
    public static AbstractReportCardnoHandler getChain () {
        AbstractReportCardnoHandler add_card_handler = SpringContextUtil.getBean(AddCardMachineReportCardnoHandler.class);
        AbstractReportCardnoHandler clear_card_handler = SpringContextUtil.getBean(ClearCardMachineReportCardnoHandler.class);
        AbstractReportCardnoHandler zju_handler = SpringContextUtil.getBean(ZJUMachineReportCardnoHandler.class);
        AbstractReportCardnoHandler normal_handler = SpringContextUtil.getBean(NormalMachineReportCardnoHandler.class);
        
        add_card_handler.setNextHandler(clear_card_handler);
        clear_card_handler.setNextHandler(zju_handler);
        zju_handler.setNextHandler(normal_handler);
        
        return add_card_handler;
    }
    
    public byte[] prehandle(String mac, String cardno) {
        if (isDueToHandle(mac, cardno)) {
            return handle(mac, cardno);
        }
        
        return getNextHandler().prehandle(mac, cardno);
        
    }
    
    protected abstract boolean isDueToHandle(String mac, String cardno);

    public abstract byte[] handle(String mac, String cardno);


    public AbstractReportCardnoHandler getNextHandler() {
        return nextHandler;
    }

    public void setNextHandler(AbstractReportCardnoHandler nextHandler) {
        this.nextHandler = nextHandler;
    }
    
    

}

 

转载于:https://www.cnblogs.com/xdxy/p/9949371.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值