一、状态模式:
首先来谈谈状态模式的定义:当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。
定义往往是那么的枯燥难懂,换一个表述方式可能更容易理解:状态模式把对象的行为包装在不同的状态对象里,每一个状态对象都有一个共同的抽象状态基类。这个表述结合状态模式的UML类图就挺好理解了,状态类StateA、SateB继承(实现)基类(接口)State,Context是State的管理类,它存有一个State的实例,即当前状态,当客户端调用其doSomething方法时,Context将调用State的doSomething方法,做对应状态的处理。
那么,状态模式可以用来处理什么问题呢?在本例中,主要解决以下问题:
1.避免多重if else的硬编码判断;
2.职责隔离,把返回码用类封装起来处理;
3.开放闭合,避免新增返回码后,需改动逻辑相关类。
二、返回码处理:
我们在开发客户端,请求服务器时,服务器会响应请求,并返回信息,这些信息中,往往包含一个字段:返回码。不同返回码,表述着本次请求不同的状态,所以我们客户端需要作出响应的处理。上代码:
Server server = new Server();
Map m = server.request();
if(m.get("return_code").toString().equals("0000")){
//doSomething
}else if(m.get("return_code").toString().equals("0001")){
//doSomething
}else if(m.get("return_code").toString().equals("0140")){
//doSomething
}
这样写的话,当我们返回码种类增多时,就要不断地增加else if,导致这个类的职责过大,代码过于臃肿。
这个时候,我们就需要状态模式了。首先,上UML类图。
首先,我们创建基类ReturnCode。
public interface ReturnCode{
void doOnReturn(Map m);
}
其次,创建其子类。
public class ReturnCode0000 implements ReturnCode{
@Override
public void doOnReturn(Map m) {
System.out.println("return code = 0000");
}
}
public class ReturnCode0001 implements ReturnCode{
@Override
public void doOnReturn(Map m) {
System.out.println("return code = 0001");
}
}
public class ReturnCode0140 implements ReturnCode{
@Override
public void doOnReturn(Map m) {
System.out.println("return code = 0140");
}
}
再者,创建上下文类:
public class RCContext {
private ReturnCode rc;
public void handleReturn(Map m){
String return_code = String.valueOf(m.get("return_code"));
if(return_code.equals("0000")){
rc = new ReturnCode0000();
rc.doOnReturn(m);
}else if(return_code.equals("0001")){
rc = new ReturnCode0001();
rc.doOnReturn(m);
}else if(return_code.equals("0140")){
rc = new ReturnCode0140();
rc.doOnReturn(m);
}
}}
客户端代码:
public class Client {
public static void main(String[] args) {
Server server = new Server();
Map m = server.request();
RCContext net = new RCContext();
net.handleReturn(m);
}
}
这样,我们就将逻辑判断交给上下文类RCContext了。但是这样的话,依然避免不了if else,每次我们新增一类返回码时,我们还需要对RCContext进行修改,违背开闭原则。这时候,则需要利用反射,通过规范命名,从类名实例化出所需要的类,优化后RCContext代码如下:
public class RCContext {
private ReturnCode rc;
public void handleReturn(Map m){
String return_code = String.valueOf(m.get("return_code"));
if(!return_code.equals("0000")){
try {//
Class clazz = Class.forName(this.getClass().getPackage().getName() + ".ReturnCode" + return_code);
rc = (ReturnCode) clazz.newInstance();
rc.doOnReturn(m);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{//返回码为0000,说明返回成功,此返回码比较频繁,因此我们直接实例化,以避免反射所带来的性能消耗
rc = new ReturnCode0000();
rc.doOnReturn(m);
}
}
}
这样,我们不仅干掉了一堆if else,并且我们如果新增返回码规则之后,只需要在指定包内新建一个ReturnCodeXXXX的类即可。