最近在维护公司项目的时候,发现了一个前辈写的一段代码,大家可以先看一下,这里为隐去了具体的实现,代码如下:
private void cmdHandler(int cmd, String data) {
switch (cmd) {
case CMD1:
//具体业务 ....
//to do ....
break;
case CMD2:
//具体业务 ....
//to do ....
break;
case CMD3:
//具体业务 ....
//to do ....
break;
case CMD4:
//具体业务 ....
//to do ....
break;
case CMD5:
//具体业务 ....
//to do ....
break;
case CMD6:
//具体业务 ....
//to do ....
break;
case CMD7:
//具体业务 ....
//to do ....
break;
case CMD8:
//具体业务 ....
//to do ....
break;
case CMD9:
//具体业务 ....
//to do ....
break;
case CMD10:
//具体业务 ....
//to do ....
break;
case CMD11:
//具体业务 ....
break;
//后面还有很多
}
}```
随着公司业务的发展具体的`CMD*`的数量还在不断的增长中,由于该类是公共服务中的一部分,每增加一个相关的业务就需要增加一个`CMD`,团队有N个程序员小哥,不同的小哥添加了不同的`CMD`而且“上”完就走,生活经验告诉我们大家一起用的东西都肯定不会有什么好结果,这个模块一样没逃脱这个悲惨的命运,现在这个类已经有几千行,充斥着迷一样的业务实现交织在一起。
![timg.jpeg](https://img.haomeiwen.com/i1857802/2873ae9b6122c12a.jpeg?imageMogr2/auto-orient/strip%7CimageView2/2/w/440)
我觉得这个图片非常直观的展现这个类也表达了我的心情,再不重构这颗雷迟早会炸,只是时间问题,作为一个有情怀的程序员😊,我怎么会让这种事情发生,下面直奔主题!
这里用到了设计模式中的 “_职责链模式(Chain of Responsibility)_ ”
>责任链模式是一种对象的行为模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。
`引用:《Java与模式》`
需要把每一个`CMD`命令抽象出来,实现成单独的职责处理对象,然后为它们提供一个公共的、抽象的父职责对象,这样就可以动态地组合职责链,当收到`CMD`命令的时候,命令会沿着链传递,传递到对应的处理者,就会被处理消耗,每个`CMD`都有具体的`Handler`处理者,实现业务代码的解耦。
首先抽象处理者
```java
public abstract class RobotHandler<D> {
protected RobotHandler<D> nextHandler;
public RobotHandler() {
}
public abstract void handle(D data);
public void setNextHandler(RobotHandler<D> handler) {
this.nextHandler = handler;
}
}```
下面创建几个具体的处理者
* CMD1
```java
public class HandleCMD1 extends RobotHandler<String> {
@Override
public void handle(int cmd,String data) {
if (cmd == 1) {
handleDeviceState(data);
} else if (nextHandler != null) {
nextHandler.handle(data);
}
}
private void handleDeviceState(String data) {
S.i("I'm HandlerCMD1 handled" + data);
}
}
- CMD2
public class HandleCMD2 extends RobotHandler<String> {
@Override
public void handle(int cmd,String data) {
if (cmd == 2) {
handleDeviceState(data);
} else if (nextHandler != null) {
nextHandler.handle(data);
}
}
private void handleDeviceState(String data) {
S.i("I'm HandlerCMD2 handled" + data);
}
}
使用方式
RobotHandler<String> handler1 = new HandleCMD1();
RobotHandler<String> handler2 = new HandleCMD2();
handler1.setNextHandler(handler2);
.
.
.
private void cmdHandler(int cmd, String data) {
handler1.handle(cmd,data);
}
到这里为止在网上搜到的大多数讲指责链模式的文章都是差不多这样实现了,看看那几十个HandleCMD
每一都要自己动手去设置setNextHandler
,且不说一手抖设错了怎么办,因为是链式结构,可能我们偶尔还需要根据使用频率将这一堆handler调整下顺序,有没有一群草泥马从眼前奔腾而过的赶脚?
为了赶走“草泥马”继续优化
public class RobotHandlerManager<D> {
private RobotHandler<D> handler;
private RobotHandlerManager(RobotHandler<D> h) {
this.handler = h;
}
public void handle(int cmd,D data) {
handler.handle(cmd,data);
}
public static class HandlersBuilder<D> {
private RobotHandler<D> header;
private RobotHandler<D> tail;
public HandlersBuilder() {
header = null;
tail = null;
}
public HandlersBuilder<D> addHandler(RobotHandler<D> handler) {
if (header == null) {
this.header = handler;
this.tail = handler;
} else {
this.tail.setNextHandler(handler);
this.tail = handler;
}
return this;
}
public RobotHandlerManager<D> build() {
return new RobotHandlerManager<>(header);
}
}
}
使用方式
RobotHandlerManager<String> handlerManager = new RobotHandlerManager.HandlersBuilder<String>()
.addHandler(new HandleCMD1())
.addHandler(new HandleCMD2())
.build();
private void cmdHandler(int cmd, String data) {
handlerManager.handle(cmd,data);
}
运行结果:
屏幕快照 2017-03-14 下午3.31.00.png从此整个世界都清净了!
demo已上传github
网友评论