没有难看的if-else的简单工厂实现
2020-11-27 本文已影响0人
n油炸小朋友
一、前言
最近接到一个任务,需要从NSQ消息队列获取业务数据,类型依靠message(16进制数)的前四位判断,判断完数据类型,再根据类型以不同的方式处理这些数据。目前推送过来的消息只有一部分类型是需要做处理的,后续还会增加其他类型的处理。
由于数据类型不单一而且要支持扩展,所以想要利用工厂设计模式,通过工厂返回可以处理该类型数据的处理类实例。可是工厂模式里面需要靠if-else做类型判断,十分丑陋,并且扩展新类型时带有侵入性,所以想了一种方法,让数据类型的枚举拥有能返回对应类型的处理器实例,这样枚举就同时能用拥有判断类型和返回对应类型处理器的功能,然后在工厂类中由这个枚举去动态地返回处理类实例,解决了问题。
二、实现
- 工厂:
@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;
}
}
- 处理类抽象接口 以及 处理类
处理器接口:
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
}
}
- 枚举以及接口
该接口返回一个数据处理类
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();
}
}
}
新增新类型
只需增加枚举类型以及处理器实现。