天天看点

行为型模式之状态模式(State)

状态模式,将条件的判断从业务逻辑中分离出去,或者说将状态的转换规则分离出去。

程序运行中所依赖的条件可视作程序的状态,程序的运行逻辑非常复杂,在不同的状态下需要有不同的表现,甚至某状态的作用要依赖另外的状态,状态模式将程序“状态”(即程序运行条件)进行了抽象,这样,通过自由切换状态条件可以方便地得到不同的表现。

我们在程序设计过程中,经常会涉及到在某些状态下进行特定的操作,一般我们会传入一个条件,然后对条件进行判断,如果是...则...,通常都会首先想到if..else..的编码方式,这种if...else的思维方式不符合面向对象的思维方式,因为这种思维是面向过程的!

这种方式的缺点很明显:

1.如果有新条件的加入则需要修改主逻辑,添加新的if..else,不符合开闭原则。

2.如果状态间有依赖关系,比如先后顺序,不容易体现和维护。

如果你的代码中出现了大片的 if ..else 那么就应该考虑使用 状态模式了,如过我们需要根据某某的状态进行操作,当它是什么的时候我们进行某某操作..我们还需要状态可以切换的,可以回退到上个状态,我们还希望能在这个状态进行完乎自动切到下个状态工作,它们的顺序是需要保证的等等,那么就应该考虑使用 状态模式了。

如果我们的程序要适应复杂的“状态变化”,那么就要使用状态模式了。

状态模式把 状态的变化规则 从业务逻辑中抽取出来,从而可以方便地改变状态,进而驱动不同的业务逻辑。

状态模式的实现通常会有一个“状态管理器”,用于管理既有状态以及将状态转换到原有业务逻辑中去。

转换规则可以在具体的状态中或状态管理器中来实现,从而与原有业务逻辑相分离。

场景:电视机在不同的频道下播放不同的节目,且我们假设老式的电视频道只能往前或往后顺序选择,不能随意选频道(即频道之间有依赖关系),根据不同的频道电视机通过查找、接收、处理等复杂的逻辑将节目播放出来。

设计:

行为型模式之状态模式(State)

示例代码:

interface ChannelState {
    String show();
    void push(ChannelStateContext ctx);
    void pull(ChannelStateContext ctx);
}
class ChannelStateContext {
    ChannelState currentState;
    ChannelStateContext(ChannelState channelState) {
        this.currentState = channelState;
    }
    void changeToNext() {
        currentState.push(this);
    }
    void changeToLast() {
        currentState.pull(this);
    }
    void setChannelState(ChannelState state) {
        currentState = state;
    }
    String action() {
        StringBuilder result = new StringBuilder("===查找信号,接收信号,处理信号... 播放节目:");// TODO 调用其它业务逻辑
        result.append(currentState.show());//调用当前状态
        return result.toString();
    }
}
class MovieChannel implements ChannelState {
    public String show() {
        return "电影";
    }
    public void push(ChannelStateContext ctx) {
        ctx.setChannelState(new MusicChannel());
    }
    public void pull(ChannelStateContext ctx) {
        ctx.setChannelState(new OtherChannel());
    }
}
class MusicChannel implements ChannelState {
    public String show() {
        return "音乐";
    }
    public void push(ChannelStateContext ctx) {
        ctx.setChannelState(new OtherChannel());
    }
    public void pull(ChannelStateContext ctx) {
        ctx.setChannelState(new MovieChannel());
    }
}
class OtherChannel implements ChannelState {
    public String show() {
        return "其它";
    }
    public void push(ChannelStateContext ctx) {
        ctx.setChannelState(new MovieChannel());
    }
    public void pull(ChannelStateContext ctx) {
        ctx.setChannelState(new MusicChannel());
    }
}
public class Test {
    public static void main(String[] args) {
        // 初始状态为电影,也可以是其它其它状态
        ChannelStateContext channelStateContext = new ChannelStateContext(new MovieChannel());// 电影
        System.out.println(channelStateContext.action());
        // 向后切换
        channelStateContext.changeToNext();// 音乐
        System.out.println(channelStateContext.action());

        channelStateContext.changeToNext();// 其它
        System.out.println(channelStateContext.action());

        channelStateContext.changeToNext();// 电影
        System.out.println(channelStateContext.action());

        // 向前切换
        channelStateContext.changeToLast();// 其它
        System.out.println(channelStateContext.action());

        channelStateContext.changeToLast();// 音乐
        System.out.println(channelStateContext.action());

        channelStateContext.changeToLast();// 电影
        System.out.println(channelStateContext.action());
    }
}
           

输出:

===查找信号,接收信号,处理信号... 播放节目:电影
===查找信号,接收信号,处理信号... 播放节目:音乐
===查找信号,接收信号,处理信号... 播放节目:其它
===查找信号,接收信号,处理信号... 播放节目:电影
===查找信号,接收信号,处理信号... 播放节目:其它
===查找信号,接收信号,处理信号... 播放节目:音乐
===查找信号,接收信号,处理信号... 播放节目:电影
           

状态模式与策略模式的区别,参见:策略模式。

继续阅读