本文正在参加「Java主题月 - Java Debug笔记活动」,详情查看 活动链接
起因
在一个阳光明媚早上,沉浸在快乐摸鱼的我,突然收到leader发给我的一个需求:大致就是A系统要给MQ的一个topic写入消息,我们的B系统消费消息做业务逻辑处理。
仔细一看这不so easy,直接一顿操作,赶在下班前写完,趁着还剩余点的时间,赶紧在摸摸鱼,坐等下班。
代码逻辑:
public interface IConsumerService {
/**
* 消费消息
* @param message
* @return
*/
boolean consumerHandler(Map<String,Object> message);
}
public class ConsumerServiceImpl implements IConsumerService {
/**
* 消息类型
*/
private static final String MSG_TYPE = "msgType";
/**
* 消息体
*/
private static final String MSG_BODY = "msgBody";
/**
* A系统过来的消息
*/
private static final String MSG_TYPE_A = "msgTypeA";
@Override
public boolean consumerHandler(Map<String, Object> message) {
if(MSG_TYPE_A.equals(message.get(MSG_TYPE))){
/// A系统消息处理逻辑
return true;
}
return false;
}
}
第二天哼着小曲走向工位时,leade拦住我说C系统也需要接进来,我心想,这不简单,不是留了一个msgType,给C系统增加个类型即可。代码修改:
public class ConsumerServiceImpl implements IConsumerService {
/**
* 消息类型
*/
private static final String MSG_TYPE = "msgType";
/**
* 消息体
*/
private static final String MSG_BODY = "msgBody";
/**
* A系统过来的消息
*/
private static final String MSG_TYPE_A = "msgTypeA";
/**
* C系统过来的消息
*/
private static final String MSG_TYPE_C = "msgTypeC";
@Override
public boolean consumerHandler(Map<String, Object> message) {
if(MSG_TYPE_A.equals(message.get(MSG_TYPE))){
/// A 系统处理逻辑
return true;
} else if(MSG_TYPE_C.equals(message.get(MSG_TYPE))){
/// C系统处理逻辑
return true;
}
return false;
}
}
第三天收到消息了,D系统也想加入。
回到工位,心想要不和C系统一样再加进去吧,反正留有类型字段msgType,来多少加多少。这样既简单有高效。
怎么办
一顿操作后,看着刚写完自己的代码,我陷入的沉思,心想要是后续F和E系统要加进来,继续这样加判断逻辑。然后会充斥着大量的if else的代码逻辑。
顿时觉得自己的代码不够优雅,那怎么办?作为有上进心的大好青年,觉得需要做出改变。
想到自己看到前几天看的策略模式,不就是可以替换大量的if else。很符合我们现在场景。
重构
先将可能需要的常量归到一个类里面去。
public interface MsgConstant {
/**
* 消息类型
*/
String MSG_TYPE = "msgType";
/**
* 消息体
*/
String MSG_BODY = "msgBody";
/**
* A系统过来的消息
*/
String MSG_TYPE_A = "msgTypeA";
/**
* C系统过来的消息
*/
String MSG_TYPE_C = "msgTypeC";
/**
* D系统过来的消息
*/
String MSG_TYPE_D = "msgTypeD";
}
对不同系统过来的消息,其实都是在处理消息,但是因系统不同,底层的处理逻辑不同,可以创建一个处理消息的接口,根据系统来创建不同实现。
public interface IMessageExecute {
/**
* 消息具体执行
* @param message
* @return
*/
boolean execute(Map<String, Object> message);
}
A系统消息:
@Service(MsgConstant.MSG_TYPE_A)
public class AMessageExecute implements IMessageExecute {
@Override
public boolean execute(Map<String, Object> message) {
// A消息的处理逻辑
return false;
}
}
C系统消息:
@Service(MsgConstant.MSG_TYPE_C)
public class CMessageExecute implements IMessageExecute {
@Override
public boolean execute(Map<String, Object> message) {
// C消息的处理逻辑
return false;
}
}
D系统消息:
@Service(MsgConstant.MSG_TYPE_D)
public class DMessageExecute implements IMessageExecute {
@Override
public boolean execute(Map<String, Object> message) {
// D消息的处理逻辑
return false;
}
}
对于消息处理的server层,我们只需要根据消息类型,获取对应的消息处理实现类即可,并且这个动作也可做到动态实现。
@Service
public class ConsumerServiceImpl implements IConsumerService {
@Autowired
private Map<String,IMessageExecute> iMessageExecuteMap;
@Override
public boolean consumerHandler(Map<String, Object> message) {
if (iMessageExecuteMap.containsKey(message.get(MsgConstant.MSG_TYPE))) {
return iMessageExecuteMap.get(MsgConstant.MSG_TYPE).execute(message);
}
return false ;
}
}
IMessageExecute的实现类会被全部注入到map中,只需从map中取出就可直接食用。
看着改造后的代码,心想后续E系统要加进来,只需为E系统去增加相关IMessageExecute的实现类,其他代码不用做任何修改,就可动态加入。
再一想,这不就是符合开闭原则,对扩展开放,对修改关闭。顿时觉得代码优雅了,摸鱼也跟自信了。
饭后思考
在适合的场景使用合适的设计模式,能让我们的代码更健壮,更简单化。在学完一种设计模式的时候,可以思考一下自己的业务代码适合这个场景,尝试去改造一下,也许就会发现新大陆。