面向对象语言开发过程中对于switch语句是很敏感的,大多数switch基本都可以通过多态方式进行重构,从而使程序获得较好的拓展能力,最近项目开发中遇到这样一个案例,在此分享一下。
重构前程序
- public void update(Request newReq){
- Request existReq=dao.getExist();
- Type _type=newReq.getMsgType();//Type为枚举类型
- ...
- switch (_type) {
- case A_MSG:
- existMsg = methodA(existReq);
- case B_MSG:
- existMsg = methodB(existReq, newReq);
- case C_MSG:
- if(...) {existReq = methodA(existReq);}
- else { existReq=methodB(existReq, newReq);}
- }
public void update(Request newReq){
Request existReq=dao.getExist();
Type _type=newReq.getMsgType();//Type为枚举类型
...
switch (_type) {
case A_MSG:
existMsg = methodA(existReq);
case B_MSG:
existMsg = methodB(existReq, newReq);
case C_MSG:
if(...) {existReq = methodA(existReq);}
else { existReq=methodB(existReq, newReq);}
}
- dao.update(existReq);
dao.update(existReq);
}
根据重构一般原则需要对_type进行抽象并建立继承关系,这里命名基类为MsgType
- public abstract MsgType{
- protected Request methodA(Request existReq,
- Request newReq) {
- ...
- }
- protected Request methodB(Request existReq) {
- ...
- }
- public abstract Request changeRequest(Request existReq, Request newReq);
- }
public abstract MsgType{
protected Request methodA(Request existReq,
Request newReq) {
...
}
protected Request methodB(Request existReq) {
...
}
public abstract Request changeRequest(Request existReq, Request newReq);
}
- 然后针对各Msg类型建立相应子类,并实现changeRequest方法
然后针对各Msg类型建立相应子类,并实现changeRequest方法
- public AMsgType extends MsgType{
- public Request changeRequest(Request existReq, Request newReq){
- return super.methodA();
- }
- }
public AMsgType extends MsgType{
public Request changeRequest(Request existReq, Request newReq){
return super.methodA();
}
}
- public BMsgType extends MsgType{
- public Request changeRequest(Request existReq, Request newReq){
- return super.methodB();
- }
- }
public BMsgType extends MsgType{
public Request changeRequest(Request existReq, Request newReq){
return super.methodB();
}
}
之后创立一个工厂方法,注意,这里仍然有一个switch,因为我们需要根据msgType来创建相应的type类。
- public class MsgTypeFactory {
- public static MsgType createMsgType(Request newReq) {
- switch (newReq.getMsgType()) {
- case A_MSG:
- return new AMsgType();
- case B_MSG:
- return new BMsgType();
- case C_MSG:
- return new CMsgType();
- default:
- throw new RuntimeException("不兼容消息类型:"+newReq.getMsgType());
- }
- }
- }
public class MsgTypeFactory {
public static MsgType createMsgType(Request newReq) {
switch (newReq.getMsgType()) {
case A_MSG:
return new AMsgType();
case B_MSG:
return new BMsgType();
case C_MSG:
return new CMsgType();
default:
throw new RuntimeException("不兼容消息类型:"+newReq.getMsgType());
}
}
}
工具已经齐备,可以向原程序开炮了,重构后程序如下:
- public void update(Request newReq){
- Request existReq=dao.getExist();
- MsgType msgType=MsgTypeFactory.createMsgType(newReq);
- //根据不同消息类型做不同作更新操作
- existReq=msgType.changeRequest(existReq, newReq);
- dao.update(existReq);
- }
public void update(Request newReq){
Request existReq=dao.getExist();
MsgType msgType=MsgTypeFactory.createMsgType(newReq);
//根据不同消息类型做不同作更新操作
existReq=msgType.changeRequest(existReq, newReq);
dao.update(existReq);
}
之前还对factory里面的switch方法耿耿于怀,以为重构前功尽弃,但是仔细一想,其实现在的程序已经完成了service层的解耦,当有一个新Msg类型添加的时候只需要增加相应的子类,在工厂方法配制一下就可以了,同样当对某个msg变更处理策略时也可以控制在很小的修改范围。
据此,我的结论是:重构过程不是一个教条的过程,或许最后还是没办法完全消灭switch,但是重构的目的达到了就已经算是成功。