状态模式:
允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。其别名为状态对象(Object for States),状态模式是一种对象行为型模式。《设计模式的艺术》
角色分析:
Context(环境类):环境类拥有各种不同状态的对象,作为外部使用的接口,负责调用状态类接口。
State(抽象状态):抽象状态既可以为抽象类,也可以直接定义成接口。主要用于定义状态抽象方法,具体实现由子类负责。
ConcreteState(具体状态类):具体状态类为抽象状态的实现者,不同的状态类对应这不同的状态,其内部实现也不相同。环境类中使用不同状态的对象时,能实现不同的处理逻辑。
很明显,处理逻辑的不是环境,而是各个状态。通过各个状态的处理,从而把逻辑流程处理完。
接下来我们就以一次网络连接作为示例,
网络请求过程一般为如下逻辑
步骤1: 初始化,看看符不符合连接协议,如果符合就到步骤2,如果不符合就到步骤5
步骤2:正式连接,连接成功,到步骤3,如果连接不成功就到步骤6
步骤3:连接成功,处理请求,处理完成到步骤4
步骤4:断开连接。
步骤5:连接失败
步骤6:尝试重连。连接成功到步骤3,连接不成功到步骤5
接下来我们就写代码来实现状态模式:
首先是简单的请求封装
public class MyRequest {
private String url; // 请求地址
private String method; // 请求方法
private boolean isMethodNessary; // 是否需要请求方法
public boolean isMethodNessary() {
return isMethodNessary;
}
public void setMethodNessary(boolean methodNessary) {
isMethodNessary = methodNessary;
}
public MyRequest(String url, String method, boolean isMethodNessary) {
this.url = url;
this.method = method;
this.isMethodNessary = isMethodNessary;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
}
接下来是抽象的连接状态:
public interface ConnectState {
void handleRequest(MyRequest request);
}
下面要实现6种连接状态:
初始化状态:
class InitState implements ConnectState{
private ConnectMachine connectMachine;
private boolean tryResult;
public InitState(ConnectMachine connectMachine) {
this.connectMachine = connectMachine;
}
@Override
public void handleRequest(MyRequest myRequest) {
tryConnect(myRequest);
}
/**
* 初始化后,如果成功,就去连接,不成功就连接失败
*/
private void tryConnect(MyRequest myRequest) {
// 尝试去连接
this.tryResult = this.tryToConnect(myRequest);
if (this.tryResult) {
this.connectMachine.goConnect(myRequest);
} else {
this.connectMachine.connectFailure(myRequest);
}
}
/**
* 初始化连接方法
* 判断请求有没有url参数,有反true,无反false
*/
private boolean tryToConnect(MyRequest myRequest){
System.out.println("与"+ myRequest.getUrl() +"连接初始化。。。。。");
if (myRequest.getUrl() != null){
return true;
}else{
return false;
}
}
}
连接状态:
public class ConnectingState implements ConnectState {
private ConnectMachine connectMachine;
private boolean connectResult;
public ConnectingState(ConnectMachine connectMachine) {
this.connectMachine = connectMachine;
}
@Override
public void handleRequest(MyRequest myRequest) {
this.goConnect(myRequest);
}
/**
* 连接方法, 连接成功就去成功处理,连接不成功就尝试重连
*/
private void goConnect(MyRequest myRequest) {
this.connectResult = this.goToConnect(myRequest);
if (this.connectResult){
this.connectMachine.connectSuccess(myRequest);
}else{
this.connectMachine.reConnect(myRequest);
}
}
/**
* 判断请求有没有方法,如果有true,没有就false
*/
private boolean goToConnect(MyRequest myRequest) {
System.out.println("正在连接。。。。。");
if (myRequest.getMethod() != null){
return true;
} else{
return false;
}
}
}
重连状态:
public class ReConnectingState implements ConnectState {
private ConnectMachine connectMachine;
private boolean reConnectResult;
public ReConnectingState(ConnectMachine connectMachine) {
this.connectMachine = connectMachine;
}
/**
* 重连 连接成功 就到成功处理,连接失败就到连接失败处理
*/
@Override
public void handleRequest(MyRequest myRequest) {
this.reConnectResult = this.reConnect(myRequest);
if (this.reConnectResult){
connectMachine.connectSuccess(myRequest);
} else {
connectMachine.connectFailure(myRequest);
}
}
/**
* 如果请求没有必要需要方法 反true,否则反false
*/
private boolean reConnect(MyRequest myRequest) {
System.out.println("尝试重连。。。。。。");
if (!myRequest.isMethodNessary()){
return true;
} else {
return false;
}
}
}
连接成功状态:
public class ConnectSuccessState implements ConnectState {
private ConnectMachine connectMachine;
private boolean handleResult;
public ConnectSuccessState(ConnectMachine connectMachine) {
this.connectMachine = connectMachine;
}
@Override
public void handleRequest(MyRequest myRequest) {
this.connectSuccessAndHandle(myRequest);
}
/**
* 处理成功就断开连接
*/
private void connectSuccessAndHandle(MyRequest myRequest) {
this.handleResult = this.handle(myRequest);
if (this.handleResult){
connectMachine.disConnect(myRequest);
}
}
/**
* 处理请求 ,处理成功 反true 处理失败false
*/
private boolean handle(MyRequest myRequest) {
System.out.println(myRequest.getUrl() + " 连接成功了,正在处理。。。。");
if (myRequest.getMethod() != null){
System.out.println(myRequest.getMethod() + " 处理成功" );
} else {
System.out.println(" 处理成功" );
}
return true;
}
}
断开连接状态:
public class DisconnectState implements ConnectState {
private ConnectMachine connectMachine;
public DisconnectState(ConnectMachine connectMachine) {
this.connectMachine = connectMachine;
}
@Override
public void handleRequest(MyRequest myRequest) {
this.disConnect(myRequest);
}
/**
* 断开连接
*/
private void disConnect(MyRequest myRequest) {
System.out.println("已经断开与" + myRequest.getUrl() + "连接");
}
}
连接失败状态:
public class ConnectFailureState implements ConnectState {
private ConnectMachine connectMachine;
public ConnectFailureState(ConnectMachine connectMachine) {
this.connectMachine = connectMachine;
}
@Override
public void handleRequest(MyRequest myRequest) {
this.connectFailure(myRequest);
}
private void connectFailure(MyRequest myRequest) {
System.out.println(myRequest.getUrl() + "连接失败。。。");
}
}
测试代码:
public class ConnectionTest {
public static void main(String[] args) {
ConnectMachine machine = new ConnectMachine();
MyRequest request = new MyRequest("www.baidu.com","search food",true);
machine.tryConnect(request);
}
}
测试结果:
与www.baidu.com连接初始化。。。。。
正在连接。。。。。
www.baidu.com 连接成功了,正在处理。。。。
search food 处理成功
已经断开与www.baidu.com连接
以上就是使用模拟的网络连接来实现状态模式。
上面的各种状态如果都写再ConnectMachine里,那么将会有一大把的if else,耦合度很高。
状态模式优缺点分析:
优点:
1)面向接口式编程,将实现细节巧妙封装在各个不同的状态类中,状态转换交给状态类自己去实现,外部无需关心;
2)将由大量业务、大量逻辑判断的代码去除,状态类内部通过状态的转换实现相关逻辑,代码可读性更好;
缺点:
1)增加新的状态时会增加状态类,而且在增加新的状态类之后,环境类需要做相应的修改,不太符合开闭原则;