Java设计模式--状态模式

状态模式【State Pattern 】

状态模式以电梯的状态转变为例。
先看下最初的类图设计。

这里写图片描述

当然这样子的设计实现起来很简单。如果再加上某个所处的状态能过渡到的状态呢?这时候就要考虑各个状态的相互转化了。

这里写图片描述

有了这张表再来设计一下类图:

这里写图片描述

定义如下的接口:

public interface ILift {
    //电梯的四个状态
    public final static int OPENING_STATE = 1; //门敞状态
    public final static int CLOSING_STATE = 2; //门闭状态
    public final static int RUNNING_STATE = 3; //运行状态
    public final static int STOPPING_STATE = 4; //停止状态;
    //设置电梯的状态
    public void setState(int state);
    //首先电梯门开启动作
    public void open();
    //电梯门有开启,那当然也就有关闭了
    public void close();
    //电梯要能上能下,跑起来
    public void run();
    //电梯还要能停下来,停不下来那就扯淡了
    public void stop();
}

那么再实现类中我们可以根据电梯所处的不同状态进行大量的判断,举个栗子:电梯门开启时

//电梯门开启
public void open() {
    //电梯在什么状态才能开启
    switch(this.state){
    case OPENING_STATE: //如果已经在门敞状态,则什么都不做
    //do nothing;
    break;
    case CLOSING_STATE: //如是电梯时关闭状态,则可以开启
    this.openWithoutLogic();
    this.setState(OPENING_STATE);
    break;
    case RUNNING_STATE: //正在运行状态,则不能开门,什么都不做
    //do nothing;
    break;
    case STOPPING_STATE: //停止状态,淡然要开门了
    this.openWithoutLogic();
    this.setState(OPENING_STATE);
    break;
    }
}

想想要是状态多的话,每个状态都要进行这样子的判断,那个代码量就真是不能见人了。还是得改善一下:

这里写图片描述

在类图中,定义了一个 LiftState 抽象类,声明了一个受保护的类型 Context 变量,这个是串联我们各个状态的封装类,封装的目的很明显,就是电梯对象内部状态的变化不被调用类知晓,也就是迪米特法则了,我的类内部情节你知道越少越好,并且还定义了四个具体的实现类,承担的是状态的产生以及状态间的转换过渡。

定义如下的抽象类:

public abstract class LiftState{
    //定义一个环境角色,也就是封装状态的变换引起的功能变化
    protected Context context;
    public void setContext(Context _context){
    this.context = _context;
    }
    //首先电梯门开启动作
    public abstract void open();
    //电梯门有开启,那当然也就有关闭了
    public abstract void close();
    //电梯要能上能下,跑起来
    public abstract void run();
    //电梯还要能停下来,停不下来那就扯淡了
    public abstract void stop();
}

下面看一下电梯停止状态时能够干的事:

public class StoppingState extends LiftState {
    //停止状态关门?电梯门本来就是关着的!
    @Override
    public void close() {
    //do nothing;
    }
    //停止状态,开门,那是要的!
    @Override
    public void open() {
    super.context.setLiftState(Context.openningState);
    super.context.getLiftState().open();
    }
    //停止状态再跑起来,正常的很
    @Override
    public void run() {
    super.context.setLiftState(Context.runningState);
    super.context.getLiftState().run();
    }
    //停止状态是怎么发生的呢?当然是停止方法执行了
    @Override
    public void stop() {
    System.out.println("电梯停止了...");
    }
}

依次类推,就可以实现不同状态的业务逻辑了。

在主类中调用时:

public class Client {
public static void main(String[] args) {
    Context context = new Context();
    context.setLiftState(new ClosingState());
    context.open();
    context.close();
    context.run();
    context.stop();
    }
}

这样就不用考虑状态的变更了,显得比较清爽。

那什么是状态模式呢?就是当一个对象内在状态改变时允许其改变行为,这个对象看起来像是改变了其类。不理解?再看:也就是说状态模式封装的非常好,状态的变更
引起了行为的变更,从外部看起来就好像这个对象对应的类发生了改变一样。

其通用的类图如下:

这里写图片描述

总结:

优点:
(1)避免了过多的 swith…case 或者 if..else 语句的使用,避免了程序的复杂性;

(2)很好的使用体现了开闭原则和单一职责原则,每个状态都是一个子类,你要增加状态就增加子类,你要修改状态,你只修改一个子类就可以了。

(3)封装性非常好,这也是状态模式的基本要求,状态变换放置到了类的内部来实现,外部的调用不用知道类内部如何实现状态和行为的变换。

缺点:
类膨胀,你想一个事物有七八、十来个状态也不稀奇,如果完全使用状态模式就会有太多的子类。

模式的选取:选取这个模式时也要考虑状态的个数。

最后:如果需要我们把已经有的几种状态按照一定的顺序再重新组装一下,那这个是什么模式?建造者模式!对,建造模式+状态模式会起到非常好的封装作用。就先这样了,以后得好好学一下模式的混编。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值