没有难看的if-else的简单工厂实现

2020-11-27  本文已影响0人  n油炸小朋友

一、前言

最近接到一个任务,需要从NSQ消息队列获取业务数据,类型依靠message(16进制数)的前四位判断,判断完数据类型,再根据类型以不同的方式处理这些数据。目前推送过来的消息只有一部分类型是需要做处理的,后续还会增加其他类型的处理。

由于数据类型不单一而且要支持扩展,所以想要利用工厂设计模式,通过工厂返回可以处理该类型数据的处理类实例。可是工厂模式里面需要靠if-else做类型判断,十分丑陋,并且扩展新类型时带有侵入性,所以想了一种方法,让数据类型的枚举拥有能返回对应类型的处理器实例,这样枚举就同时能用拥有判断类型和返回对应类型处理器的功能,然后在工厂类中由这个枚举去动态地返回处理类实例,解决了问题。

二、实现

  1. 工厂:
@Component
public class MiYueDataProcessorFactory {

    // 数据类型字段长度
    private static final Integer PREX_LENGTH = 4;

    public ProcessorBase getBy(byte[] msg) {

        if (msg == null || msg.length <= 0) {
            return null;
        }

        // 转换成16进制
        String msgStr = StringTool.byteArray2HexString(msg);

        if (StringUtils.isNotBlank(msgStr) && msgStr.length() >= PREX_LENGTH) {
            String prex = msgStr.substring(0, PREX_LENGTH);
            if (StringUtils.isNotBlank(prex)) {
                // 获取枚举
                MiYueDataTypeEnum miYueDataTypeEnum = MiYueDataTypeEnum.get(prex);
                if (miYueDataTypeEnum != null) {
                    // 返回处理类
                    return miYueDataTypeEnum.returnProcessor();
                }
            }
        }
        return null;
    }
}
  1. 处理类抽象接口 以及 处理类
    处理器接口:
public interface ProcessorBase {
    // 处理数据
    void process(byte[] data);
}

某个处理器实现类:

@Component
public class AttendanceProcessor implements ProcessorBase {

    public static AttendanceProcessor attendanceProcessor;

    @Autowired
    private ApplicationContext applicationContext;

    @PostConstruct
    public void init() {
        // 注入静态的属性
        attendanceProcessor = (AttendanceProcessor) applicationContext.getBean("attendanceProcessor");
    }


    @Override
    public void process(byte[] data) {
        // TODO
    }


}
  1. 枚举以及接口
    该接口返回一个数据处理类
public interface MiYueDataTypeProcessorReturner {
    ProcessorBase returnProcessor();
}

枚举:

@Getter
@AllArgsConstructor
public enum MiYueDataTypeEnum implements MiYueDataTypeProcessorReturner {


    ATTENDANCE("1234", "考勤") {
        @Override
        public ProcessorBase returnProcessor() {
            return AttendanceProcessor.attendanceProcessor;
        }
    };

    private static final Map<String, MiYueDataTypeEnum> ENUM_VALUE_MAP = Maps.newHashMap();

    static {
        for (MiYueDataTypeEnum typEnum : MiYueDataTypeEnum.values()) {
            ENUM_VALUE_MAP.put(typEnum.getPrex(), typEnum);
        }
    }

    private String prex;
    private String reasonPhrase;

    public static MiYueDataTypeEnum get(String prex) {
        if (StringUtils.isBlank(prex)) {
            return null;
        }
        return ENUM_VALUE_MAP.get(prex);
    }

}

4.使用

@Component
@Slf4j
public class NsqMsgDeal implements NSQMessageCallback {

    @Autowired
    private MiYueDataProcessorFactory factory;

    @Override
    public void message(NSQMessage nsqMessage) {
        try {
            // 获取处理类
            ProcessorBase processor = factory.getBy(nsqMessage.getMessage());
            if (processor != null) {
                // 处理数据
                processor.process(nsqMessage.getMessage());
            }
        } catch (Exception e) {
            // 数据处理异常处理。。。
        } finally {
            nsqMessage.finished();
        }
    }
}

新增新类型

只需增加枚举类型以及处理器实现。

上一篇下一篇

猜你喜欢

热点阅读