java状态模式实例解析

状态模式是一种常用的设计模式,常用于软件系统中解决多种状态下行为互异的情况。例如在音视频播放器中多种状态各自对应着不相同的处理,使用状态机可以完美实现解耦。最近在做一个项目的重构,有使用到状态模式,因此写这篇文章分享一下。

1、状态模式概述:

状态模式(State Pattern):允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。其别名为状态对象(Object for States),状态模式是一种对象行为型模式。《设计模式的艺术》

image.png

1)Context(环境类):环境类拥有各种不同状态的对象,作为外部使用的接口,负责调用状态类接口。
2)State(抽象状态):抽象状态既可以为抽象类,也可以直接定义成接口。主要用于定义状态抽象方法,具体实现由子类负责。
3)ConcreteState(具体状态类):具体状态类为抽象状态的实现者,不同的状态类对应这不同的状态,其内部实现也不相同。环境类中使用不同状态的对象时,能实现不同的处理逻辑。

2、状态模式示例:

示例为真实项目,一个即时通讯客户端连接服务端网络的设计。客户端连接服务器时存在多种状态,最初是通过if-else判断来实现,代码耦合度比较高。使用状态设计模式之后,代码清晰很多,耦合降低。类图与上面的基本一样,因此此处不再展示,直接上代码。

public interface ConnectState {

    void handleRequest();
}
public class InitState implements ConnectState{

    private ConnectMachine connectMachine;

    private boolean connectResult;

    public InitState(ConnectMachine connectMachine) {
        this.connectMachine = connectMachine;
    }

    @Override
    public void handleRequest() {
        doConnect();
        connectMachine.waitingConnect();
    }

    private void doConnect() {
        //connect server
        if (connectResult) {
            connectSuccess();
        } else {
            connectFailure();
        }
    }

    private void connectSuccess() {
        connectMachine.connectSuccess();
    }

    private void connectFailure() {
        connectMachine.connectFailure();
    }
}
public class ConnectingState implements ConnectState{

    private ConnectMachine connectMachine;

    public ConnectingState(ConnectMachine connectMachine) {
        this.connectMachine = connectMachine;
    }

    @Override
    public void handleRequest() {
        waitingConnect();
    }

    private void waitingConnect() {
        //loading and do something
    }
}
public class ConnectSuccessState implements ConnectState{

    private ConnectMachine connectMachine;

    public ConnectSuccessState(ConnectMachine connectMachine) {
        this.connectMachine = connectMachine;
    }

    @Override
    public void handleRequest() {
        connectSuccess();
    }

    private void connectSuccess() {
        //do something
    }
}
public class ConnectFailureState implements ConnectState{

    private ConnectMachine connectMachine;

    public ConnectFailureState(ConnectMachine connectMachine) {
        this.connectMachine = connectMachine;
    }

    @Override
    public void handleRequest() {
        connectFailure();
    }

    private void connectFailure() {
        //do something
    }
}
public class ReConnectingState implements ConnectState{

    private ConnectMachine connectMachine;

    public ReConnectingState(ConnectMachine connectMachine) {
        this.connectMachine = connectMachine;
    }

    @Override
    public void handleRequest() {
        reConnect();
    }

    private void reConnect() {
        //disconnect old connect and connect again
        connectMachine.disConnect();
        connectMachine.doConnect();
    }
}
public class DisconnectState implements ConnectState {

    private ConnectMachine connectMachine;

    public DisconnectState(ConnectMachine connectMachine) {
        this.connectMachine = connectMachine;
    }

    @Override
    public void handleRequest() {
        disConnect();
    }

    private void disConnect() {
        //do something
    }
}
public class ConnectMachine {

    private ConnectState initState;
    private ConnectState connectingState;
    private ConnectState reconnectState;
    private ConnectState disConnectState;
    private ConnectState connectSuccessState;
    private ConnectState connectFailureState;

    public ConnectMachine() {
        initState = new InitState(this);
        connectingState = new ConnectingState(this);
        reconnectState = new ReConnectingState(this);
        disConnectState = new DisconnectState(this);
        connectSuccessState = new ConnectSuccessState(this);
        connectFailureState = new ConnectFailureState(this);
    }

    public void doConnect() {
        initState.handleRequest();
    }

    public void waitingConnect() {
        connectingState.handleRequest();
    }

    public void reConnect() {
        reconnectState.handleRequest();
    }

    public void disConnect() {
        disConnectState.handleRequest();
    }

    public void connectSuccess() {
        connectSuccessState.handleRequest();
    }

    public void connectFailure() {
        connectFailureState.handleRequest();
    }
}

如果不使用状态模式,所有的逻辑判断全部写在ConnectMachine类里面,而且是通过大量if-else判断实现,代码可读性比较差。改成状态模式之后,实现细节交给具体状态类去实现,ConnectMachine只是提供给外部系统使用的接口,具体实现对于用户来说是不可的。因为只是展示状态模式的设计,使用的是回调的方式,在项目中使用时可以引入Rxjava,响应式编程更加能体会到其中妙处。

3、状态模式优缺点分析:

优点:

1)面向接口式编程,将实现细节巧妙封装在各个不同的状态类中,状态转换交给状态类自己去实现,外部无需关心;
2)将由大量业务、大量逻辑判断的代码去除,状态类内部通过状态的转换实现相关逻辑,代码可读性更好;

缺点:

1)增加新的状态时会增加状态类,而且在增加新的状态类之后,环境类需要做相应的修改,不太符合开闭原则;

结束语

状态模式的介绍就到这,虽然状态模式在设计上能够带来很大优势。但是也不能滥用,因为对于一些简单的逻辑,随意使用状态模式会使得系统复杂度增加。如果对设计模式感兴趣的同学,推荐读一下《设计模式的艺术》这本书,写得很实用。

猜你喜欢

转载自blog.csdn.net/hb_csu/article/details/80525744