项目中有个业务处理类大小117K,代码2700行,看此类差点雷死我,如今如要增加业务逻辑大约20个吧,此类如果随着项目工程的二期、三期如次添加逻辑迟早有一天大小达到M,噢、mygod。细心研读前人的工作总结,发现其中有点可改造的蛛丝马迹(本人很笨、别笑我才发现如何改造)。
下面我们对业务流程、以及涉及的相关类进行介绍,Msg代表接受到客户端的一个消息报文,消息报文结构:消息头+消息体,消息头参数固定、消息体参数不定,下面是一个简单的类图,这只是一个模拟场景,****Req代表各户端请求类,***Rsp代表返回给客户端的参数类。实际比此复杂,为描述问题我们简单摘除几个类介绍,别问我为何这么设计继承。类图msg与msgHead是组合关系也许画错了、不当之处请指出,勿恶语向伤;
//类中主要方法如下 public void execute(Object object) { Message message = (Message)object; int opcode = message.getOpcode(); int connectId = message.getConnectId(); //消息头已经解析,获取消息体,即子类属性字节数组 byte[] bytes = message.getBytes(); if (opcode == MsgInfo.ADD_RING) { // 订购彩铃 orderRing(connectId, bytes); } else if (opcode == MsgInfo.PRESENT_RING) { // 赠送彩铃 presentRing(connectId, bytes); } else if (opcode == MsgInfo.DEL_RING) { // 删除个人铃音 delPersonalRing(connectId, bytes); } //此处省略n个else if } //其他删除、赠送与省略的else if中的处理逻辑与之基本相同 private void orderRing(int connectId, byte[] bytes) { //处理方法分为四步,具体代码省略 //1、解析字节数组为订购铃音类 //2、处理订购关系 //3、处理结果封装为订购响应类 //4、发送回客户端 } //省略presentRing、delPersonalRing等一系列其他方法,所有的处理方法参数相同……
鉴于此、想到使用命令模式改造此类,如果不了解命令模式请阅读相关书籍,大话设计模式或设计与模式,这里我们仅给出大致的定于与类图。
何谓命令模式:将一个请求封装为一个对象,从而是你可用不同的请求对客户端参数化,对请求排队或记录日志,以及支持可撤销的操作。
Shit、这句话很难理解哦,那就先别理解了,我们看下命令模式的类图,然后介绍如何使用命令模式改造上面的elseif。
类图先省略,上班偷空写的;
下面进入正题,对Handler小手术开始,主要考虑如下:
1、提炼方法
将每个if语句块中的逻辑提取为一个方法,这里我们的handler已经实现,就是:orderRing、presentRing、delPersonalRing、……。
2、提炼类
将每个业务处理方法提取为以各类,然后对具体类进行抽象,提取父类或者接口;代码如下:
public Abstract class Command{ public void execute() } public class OrderRingCommand extends Command { private Handler hander; public OrderRingCommand(Handler hander){ this.hander = hander; } public void execute(int connectId, byte[] bytes){ //1、解析字节数组为订购铃音类 //2、增加订购关系 //3、处理结果封装为订购响应类 //4、发送回客户端 } /** * 1、解析字节数组为订购铃音类 */ public void method1(){ } /** * 2、处理订购关系 */ public void method2(){ } /** * 3、处理结果封装为订购响应类 */ public void method3(){ } /** * 4、结果发送回客户端 */ public void method4(){ } } public class DelRingCommand extends Command { private Handler hander; public DelRingCommand(Handler hander){ this.hander = hander; } public void execute(int connectId, byte[] bytes){ //1、解析字节数组为订购铃音类 //2、删除购关系 //3、处理结果封装为订购响应类 //4、发送回客户端 } //提取方法 }
3、命令模式改造替换elseif:
Map<Integer, Command> map = new HashMap<Integer,Command>(); static{ map.put(MsgInfo.ADD_RING, new OrderRingCommand()); //省却其他,这里仅为演示,实际项目中实例化类通过spring容器或者其他方法 } public void execute(Object object) { Message message = (Message)object; int opcode = message.getOpcode(); int connectId = message.getConnectId(); //消息头已经解析,获取消息体,即子类属性字节数组 byte[] bytes = message.getBytes(); map.get(opcode).execute(connectId,bytes); }
命令模式替换else if代码坏味道的重构结束,众多的if条件块烟消云散,取而代之的是一个个精简的类,doc版本在附件中