zoukankan      html  css  js  c++  java
  • 设计模式(策略、工厂、模板、责任链)的使用实例

    业务背景

    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;
        }
        
        
    
    }
  • 相关阅读:
    POJ 1887 Testing the CATCHER
    HDU 3374 String Problem
    HDU 2609 How many
    POJ 1509 Glass Beads
    POJ 1458 Common Subsequence
    POJ 1159 Palindrome
    POJ 1056 IMMEDIATE DECODABILITY
    POJ 3080 Blue Jeans
    POJ 1200 Crazy Search
    软件体系结构的艺术阅读笔记1
  • 原文地址:https://www.cnblogs.com/xdxy/p/9949371.html
Copyright © 2011-2022 走看看