状态模式

原创 2016年08月29日 13:44:55

我们开发项目的过程中通常会碰到一种需求,某个对象包含多种状态变化的可能性,随着状态的变化行为也执行不同的动作。

以电梯来举例:
电梯最基本具备 开门、关门、上下走动、停止 这四种状态。状态与状态之间有约束的关系,比如只能在关门的情况下才能走动。
所以用传统面向过程的解决方案,就必须要用状态值来标记每一种状态,然后用多个if else语句来判断状态的执行顺序,每当增加一个新状态的时候就需要重新修改代码,这样就不符合开闭原则。

我们来看下如何用状态模式来优雅的处理问题。

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 stop();  //电梯停止
    public abstract void run();   //电梯上下走动
}
//电梯处于开门状态
public class OpenState extends LiftState
{
    @Override
    public void open() {
        //本身就处于开门状态
        //do nothing
    }
    @Override
    public void close() {
        super.context.setLiftStatus(Context.closeState);  //切换至关门状态
        super.context.getLiftStatus().close(); //委托关门状态类 来执行具体的关门动作
    }
    @Override
    public void stop() {
        //电梯开门状态时,本身就停止的
        //do nothing
    }
    @Override
    public void run() {
        //电梯开门状态时,不能走动
        //do nothing
    }
}
//电梯走动状态
public class RunState extends LiftState
{
    @Override
    public void open() {
        //走动状态不能开门
        //do nothing
    }
    @Override
    public void close() {
        //走动状态本身就是处于关门状态
        //do nothing
    }
    @Override
    public void stop() {
        super.context.setLiftStatus(Context.stopState);  //切换至停止状态
        super.context.getLiftStatus().stop(); //委托停止状态类 来执行具体的停止动作
    }
    @Override
    public void run() {
        //本身就处于走动状态
        //do nothing
    }
}
//电梯关门状态类
public class CloseState extends LiftState
{
    @Override
    public void open() {
        super.context.setLiftStatus(Context.openStatus);  //切换至开门状态
        super.context.getLiftStatus().open(); //委托开门状态类 来执行具体的开门动作
    }
    @Override
    public void close() {
    }
    @Override
    public void stop() {
    }
    @Override
    public void run() {
        super.context.setLiftStatus(Context.runState);  //切换至走动状态
        super.context.getLiftStatus().run(); //委托走动状态类 来执行具体的走动动作
    }
}
//电梯停止状态类
public class StopState extends LiftState
{
    @Override
    public void open() {
        super.context.setLiftStatus(Context.openStatus);  //切换至开门状态
        super.context.getLiftStatus().open(); //委托开门状态类 来执行具体的走动动作
    }
    @Override
    public void close() {
    }
    @Override
    public void stop() {
    }
    @Override
    public void run() {
        super.context.setLiftStatus(Context.runState);  //切换至走动状态
        super.context.getLiftStatus().run(); //委托走动状态类 来执行具体的走动动作
    }
}
public class Context
{
    public final static OpenState openStatus = new OpenState();
    public final static CloseState closeState = new CloseState();
    public final static RunState runState = new RunState();
    public final static StopState stopState = new StopState();
    private LiftState curStatus; //当前电梯状态
    //设置电梯状态,并且把当前上下文的引用传递给具体的状态类,具体的状态类通过上下文的引用切换不同的状态。
    public void setLiftStatus(LiftState liftStatus)
    {
        curStatus = liftStatus;
        liftStatus.setContext(this);
    }
    //获取当前的电梯状态
    public LiftState getLiftStatus()
    {
        return curStatus;
    }
    public void open()
    {
        curStatus.open();
    }
    public void close()
    {
        curStatus.close();
    }
    public void stop()
    {
        curStatus.stop();
    }
    public void run()
    {
        curStatus.run();
    }
}
//客户端类
public class Client
{
    public static void main()
    {
        Context context = new Context();
        context.setLiftStatus(new CloseState());  //电梯初始化为关门状态
        context.open();
        context.close();
        context.run();
        context.stop();
    }
}

需要说明的一点是:
Context 是一个上下文角色,它的作用就是串联各个状态的过渡,在LifeState抽象类中我们定义了并把这个上下文组合进来,病传递到了子类。也就是四个具体状态类根据上下文的环境来决定如何进行状态的过渡。

状态模式的优点:
首先,每个状态类都很简洁,同时也不需要用 if else 来判断状态的切换。
同时,如果我们要新增状态只需要创建新的状态类即可,是通过扩展而非修改的方式来实现功能,这是面向对象的一个重要原则,开闭原则。非常完美。

【设计模式】学习笔记14:状态模式(State)

认识状态模式 假设有一个糖果机, 它的工作状态图如下:要用代码实现糖果机的功能, 如果不用状态模式: 一种方法是创建一个类,它的作用就是一个状态机,对每一个动作,我们都创建了一个对应的方法,这些方法...
  • shuangde800
  • shuangde800
  • 2013年08月22日 00:15
  • 19519

透过android案例熟知状态模式(二)

前面一篇博客是用简单java例子来熟悉状态设计模式,而这篇我将以android登录的例子继续讲解状态设计模式。 一.android中状态设计模式应用场景 在android开发中,我们遇到登录界面是...
  • u014115577
  • u014115577
  • 2016年09月18日 16:50
  • 1349

Java设计模式之状态模式

本文属于"23种设计模式"系列,介绍状态模式。
  • jason0539
  • jason0539
  • 2015年04月14日 07:54
  • 14028

状态模式小例子

  • 2014年06月08日 11:36
  • 5.32MB
  • 下载

每天感悟总结-状态模式State

  • 2009年03月10日 15:12
  • 2KB
  • 下载

状态模式代码

  • 2007年10月12日 13:16
  • 28KB
  • 下载

状态模式Demo

  • 2017年05月12日 10:57
  • 22.39MB
  • 下载

OO设计和伪状态模式实现的控制台五子棋游戏

  • 2017年02月13日 09:16
  • 184KB
  • 下载

状态模式及具体实现

  • 2014年02月06日 16:23
  • 58KB
  • 下载

Headfirst(十)状态模式C++实现

  • 2015年10月21日 15:38
  • 1.51MB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:状态模式
举报原因:
原因补充:

(最多只允许输入30个字)