Java运用策略模式+简单工厂消除if-else

1、问题场景

        监听上游服务MQ消息,根据不同的操作类型(opCode)做相对应的个性化处理。目前接收的就三种,随着业务拓展还会不断的增加,所以此处按照原来的if-else去处理会显得比较呆。

2、一般实现(if-else)

public Action consume(Message message, ConsumeContext context) {
        boolean success = true;
        long startTime = System.currentTimeMillis();
        try {
            String content = new String(message.getBody(), StandardCharsets.UTF_8);
            log.info("op_message_listener receive_msg: {}", content);
            DetailsDO detailsDO = JSONObject.parseObject(content, DetailsDO.class);
            String opCode = detailsDO.getOpCode().getCode();
            if (OpCodeEnum.OP_CODE_100.getCode().equals(opCode)) {
                opCode_100(detailsDO);
            } else if (OpCodeEnum.OP_CODE_110.getCode().equals(opCode)) {
                opCode_110(detailsDO);
            } else if (OpCodeEnum.OP_CODE_120.getCode().equals(opCode)) {
                opCode_120(detailsDO);
            }
        } catch (Exception e) {
            success = false;
            log.error("op_message_listener handle_error", e);
        }
        MonitorLogUtil.addSunFireLog("op_message_listener_事件操作消息监听" + "#" + "message.getMsgID()", startTime, success);
        return (success || !errorRetry) ? Action.CommitMessage : Action.ReconsumeLater;
}

以上代码实现有如下的缺点:

  • 不易于扩展,增加一个新的渠道需要改变原有的代码,不符合开放封闭原则
  • 使用多重条件选择语句,随着业务拓展if-else会越来越多,不符合面向对象设计思想
  • 代码糅合在一起,不利于阅读和维护,不符合单一职责原则

针对以上代码的缺点我们可以利用策略模式来消除臃肿复杂的if-else。

3、策略+简单工厂

        策略模式(Strategy Pattern)定义了一组策略,分别在不同类中封装起来,每种策略都可以根据当前场景相互替换,从而使策略的变化可以独立于操作者。比如我们要去某个地方,会根据距离的不同(或者是根据手头经济状况)来选择不同的出行方式(共享单车、坐公交、滴滴打车等等),这些出行方式即不同的策略。

        简单工厂提供一个创建对象实例的功能,而无须关心其具体实现。被创建实例的类型可以是接口、抽象类,也可以是具体的类。

3.1、定义抽象的数据策略接口

public interface IEventService {

    void opHandler(DetailsDO detailsDO);

    String getOpCode();

}

其中的opHandler方法是执行具体匹配数据逻辑的接口

3.2、具体策略实现类

@Slf4j
@Service("xxxEventService")
public class XxxEventServiceImpl implements IEventService {

    @Override
    public void opHandler(DetailsDO detailsDO) {
        // 业务逻辑实现
        System.out.println("------xxx opHandler------");
    }
    
    @Override
    public String getOpCode() {
        return OpCodeEnum.OP_CODE_100.getCode();
    }
    
}

3.3、定义策略工厂

@Component
public class EventServiceFactory implements InitializingBean, ApplicationContextAware {

    private ApplicationContext appContext;

    private static final Map EVENT_SERVICE_MAP = new HashMap<>(8);

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        appContext = applicationContext;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        // 将 Spring 容器中所有的 IEventService 注册到 EVENT_SERVICE_MAP
        appContext.getBeansOfType(IEventService.class)
                  .values()
                  .forEach(handler -> EVENT_SERVICE_MAP.put(handler.getOpCode(), handler));
    }

    public static IEventService getHandler(String opCode) {
        return EVENT_SERVICE_MAP.get(opCode);
    }
}

3.4、调用实现

public Action consume(Message message, ConsumeContext context) {
        boolean success = true;
        long startTime = System.currentTimeMillis();
        try {
            String content = new String(message.getBody(), StandardCharsets.UTF_8);
            log.info("op_message_listener receive_msg: {}", content);
            DetailsDO detailsDO = JSONObject.parseObject(content, DetailsDO.class);
            String opCode = detailsDO.getOpCode().getCode();
            // 替换if-else --begin
            IEventService eventService = EventServiceFactory.getHandler(opCode);
            eventService.opHandler(detailsDO);
            // 替换if-else --end
        } catch (Exception e) {
            success = false;
            log.error("op_message_listener handle_error", e);
        }
        MonitorLogUtil.addSunFireLog("op_message_listener_事件操作消息监听" + "#" + "message.getMsgID()", startTime, success);
        return (success || !errorRetry) ? Action.CommitMessage : Action.ReconsumeLater;
    }

4、优缺点总结

4.1、优点

  • 易于扩展,增加一个新的策略只需要添加一个具体的策略实现类即可,基本不需要改变原有的代码,符合开放封闭原则
  • 避免使用多重条件选择语句,充分体现面向对象设计思想
  • 策略类之间可以自由切换,由于策略类都实现同一个接口,所以使它们之间可以自由切换
  • 每个策略类使用一个策略类,符合单一职责原则
  • 客户端与策略算法解耦,两者都依赖于抽象策略接口,符合依赖反转原则
  • 客户端不需要知道都有哪些策略类,符合最小可用原则

4.1、缺点

  • 策略模式,当策略算法太多时,会造成很多的策略类

你可能感兴趣的:(java基础,java,策略模式,开发语言)