状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。

直接看定义好像有些晦涩,我们先看例子,待会儿再回到定义来。

我们现在模拟一个糖果机的工作状态,它的状态变化图如下所示

找出所有的状态:

  • 没有25分钱
  • 有25分钱
  • 糖果售罄
  • 售出糖果

现在我们需要用代码来实现这些状态。我们可以创建一个实例变量来持有目前的状态,然后定义每个状态的值:

final static int SOLD_OUT=0;
final static int NO_QUARTER=1;
final static int HAS_QUARTER=2;
final static int SOLD=3; int state =SOLD_OUT;

但是显然可以预见的是,这种做法会带来一个弊端,当你需要扩展状态时,修改代码会变得非常困难。比如说,我们需要为糖果机新增一个功能,“售出糖果”状态有10%的几率会导致掉下两颗糖果,而不是一颗,这显然需要增加一个状态,用原有的实现方式会让我们陷入混乱的状态中无法脱身。

为此,我们应该试着局部化每个状态的行为,遵守“封装变化”原则,将每个状态的行为都放在各自的类中,那么每个状态只要实现它自己的动作就可以了。我们要做的事情是

  • 我们可以定义一个State接口,在这个接口内,糖果机的每个动作都有一个对应的方法。
  • 然后为机器中的每个状态实现状态类。这些类将负责在对应的状态下进行机器的行为。
  • 最后,将动作委托到状态类。

State接口

public interface State {public void insertQuarter();public void ejectQuarter();public void turnCrank();public void dispense();
}

每个状态对应的状态类

import java.util.Random;public class HasQuarterState implements State {Random randomWinner = new Random(System.currentTimeMillis());GumballMachine gumballMachine;public HasQuarterState(GumballMachine gumballMachine) {this.gumballMachine = gumballMachine;}public void insertQuarter() {System.out.println("You can't insert another quarter");}public void ejectQuarter() {System.out.println("Quarter returned");gumballMachine.setState(gumballMachine.getNoQuarterState());}public void turnCrank() {System.out.println("You turned...");int winner = randomWinner.nextInt(10);if ((winner == 0) && (gumballMachine.getCount() > 1)) {gumballMachine.setState(gumballMachine.getWinnerState());} else {gumballMachine.setState(gumballMachine.getSoldState());}}public void dispense() {System.out.println("No gumball dispensed");}public String toString() {return "waiting for turn of crank";}
}
public class NoQuarterState implements State {GumballMachine gumballMachine;public NoQuarterState(GumballMachine gumballMachine) {this.gumballMachine = gumballMachine;}public void insertQuarter() {System.out.println("You inserted a quarter");gumballMachine.setState(gumballMachine.getHasQuarterState());}public void ejectQuarter() {System.out.println("You haven't inserted a quarter");}public void turnCrank() {System.out.println("You turned, but there's no quarter");}public void dispense() {System.out.println("You need to pay first");} public String toString() {return "waiting for quarter";}
}
public class SoldOutState implements State {GumballMachine gumballMachine;public SoldOutState(GumballMachine gumballMachine) {this.gumballMachine = gumballMachine;}public void insertQuarter() {System.out.println("You can't insert a quarter, the machine is sold out");}public void ejectQuarter() {System.out.println("You can't eject, you haven't inserted a quarter yet");}public void turnCrank() {System.out.println("You turned, but there are no gumballs");}public void dispense() {System.out.println("No gumball dispensed");}public String toString() {return "sold out";}
}
public class SoldState implements State {GumballMachine gumballMachine;public SoldState(GumballMachine gumballMachine) {this.gumballMachine = gumballMachine;}public void insertQuarter() {System.out.println("Please wait, we're already giving you a gumball");}public void ejectQuarter() {System.out.println("Sorry, you already turned the crank");}public void turnCrank() {System.out.println("Turning twice doesn't get you another gumball!");}public void dispense() {gumballMachine.releaseBall();if (gumballMachine.getCount() > 0) {gumballMachine.setState(gumballMachine.getNoQuarterState());} else {System.out.println("Oops, out of gumballs!");gumballMachine.setState(gumballMachine.getSoldOutState());}}public String toString() {return "dispensing a gumball";}
}
public class WinnerState implements State {GumballMachine gumballMachine;public WinnerState(GumballMachine gumballMachine) {this.gumballMachine = gumballMachine;}public void insertQuarter() {System.out.println("Please wait, we're already giving you a Gumball");}public void ejectQuarter() {System.out.println("Please wait, we're already giving you a Gumball");}public void turnCrank() {System.out.println("Turning again doesn't get you another gumball!");}public void dispense() {System.out.println("YOU'RE A WINNER! You get two gumballs for your quarter");gumballMachine.releaseBall();if (gumballMachine.getCount() == 0) {gumballMachine.setState(gumballMachine.getSoldOutState());} else {gumballMachine.releaseBall();if (gumballMachine.getCount() > 0) {gumballMachine.setState(gumballMachine.getNoQuarterState());} else {System.out.println("Oops, out of gumballs!");gumballMachine.setState(gumballMachine.getSoldOutState());}}}public String toString() {return "despensing two gumballs for your quarter, because YOU'RE A WINNER!";}
}

下面是我们的糖果机代码

public class GumballMachine {State soldOutState;State noQuarterState;State hasQuarterState;State soldState;State winnerState;State state = soldOutState;int count = 0;public GumballMachine(int numberGumballs) {soldOutState = new SoldOutState(this);noQuarterState = new NoQuarterState(this);hasQuarterState = new HasQuarterState(this);soldState = new SoldState(this);winnerState = new WinnerState(this);this.count = numberGumballs;if (numberGumballs > 0) {state = noQuarterState;} }public void insertQuarter() {state.insertQuarter();}public void ejectQuarter() {state.ejectQuarter();}public void turnCrank() {state.turnCrank();state.dispense();}void setState(State state) {this.state = state;}void releaseBall() {System.out.println("A gumball comes rolling out the slot...");if (count != 0) {count = count - 1;}}int getCount() {return count;}void refill(int count) {this.count = count;state = noQuarterState;}public State getState() {return state;}public State getSoldOutState() {return soldOutState;}public State getNoQuarterState() {return noQuarterState;}public State getHasQuarterState() {return hasQuarterState;}public State getSoldState() {return soldState;}public State getWinnerState() {return winnerState;}public String toString() {StringBuffer result = new StringBuffer();result.append("\nMighty Gumball, Inc.");result.append("\nJava-enabled Standing Gumball Model #2004");result.append("\nInventory: " + count + " gumball");if (count != 1) {result.append("s");}result.append("\n");result.append("Machine is " + state + "\n");return result.toString();}
}

测试代码如下

public class GumballMachineTestDrive {public static void main(String[] args) {GumballMachine gumballMachine = new GumballMachine(10);System.out.println(gumballMachine);gumballMachine.insertQuarter();gumballMachine.turnCrank();gumballMachine.insertQuarter();gumballMachine.turnCrank();System.out.println(gumballMachine);gumballMachine.insertQuarter();gumballMachine.turnCrank();gumballMachine.insertQuarter();gumballMachine.turnCrank();System.out.println(gumballMachine);gumballMachine.insertQuarter();gumballMachine.turnCrank();gumballMachine.insertQuarter();gumballMachine.turnCrank();System.out.println(gumballMachine);gumballMachine.insertQuarter();gumballMachine.turnCrank();gumballMachine.insertQuarter();gumballMachine.turnCrank();System.out.println(gumballMachine);gumballMachine.insertQuarter();gumballMachine.turnCrank();gumballMachine.insertQuarter();gumballMachine.turnCrank();System.out.println(gumballMachine);}
}

测试结果为

现在我们回到文章开头状态模式的定义,这个描述的第一部分“状态模式允许对象在内部状态改变时改变它的行为”附有相当多的涵义,因为这个模式将状态封装成独立的类,并将动作委托到代表当前状态的对象,行为会随着内部的状态改变而改变。

定义的第二部分“对象看起来好像修改了它的类”是什么意思呢?从客户的视角看:如果你使用的对象能够完全改变它的行为,那么你会觉得,这个对象实际上是从别的类实例化而来的。然而,实际上,我们是在使用组合通过简单引用不同的状态对象来造成类改变的假象。

状态模式的类图为

状态模式和策略模式

我们把策略模式想成是除了继承之外的一种弹性替代方案。如果你继承定义了一个类的行为,你将被这个行为困住,甚至要修改它都很难。有了策略模式,你可以通过组合不同的对象来改变行为。

我们把状态模式想成是不用再context中放置许多条件判断的替代方案。通过将行为包装进状态对象中,你可以通过在context内简单地改变状态对象来改变context的行为。

设计模式(12)——状态模式相关推荐

  1. java设计模式 连续处理_Java 设计模式(12) —— 状态模式

    一.状态模式 能根据内部状态的变化,改变对象的行为,看起来好像修改了类 状态模式 二.示例 智能糖果机:需要设计一款自助购买的糖果机,糖果机的状态有 准备使用(接下来可投入硬币) 投入硬币(接下来可摇 ...

  2. python的编程模式-Python设计模式之状态模式原理与用法详解

    本文实例讲述了Python设计模式之状态模式原理与用法.分享给大家供大家参考,具体如下: 状态模式(State Pattern):当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类 ...

  3. 【转】设计模式 ( 十七) 状态模式State(对象行为型)

    设计模式 ( 十七) 状态模式State(对象行为型) 1.概述 在软件开发过程中,应用程序可能会根据不同的情况作出不同的处理.最直接的解决方案是将这些所有可能发生的情况全都考虑到.然后使用if... ...

  4. 码农小白 设计模式篇 状态模式

    码农小白 设计模式篇 状态模式 1.状态的认识 2.面向过程思维的代码实现 小结: 3.面向对象实现 小结 4.用状态模式实现 1.状态模式的简介 2.状态模式的好处 3.状态模式的使用 4.代码实现 ...

  5. 设计模式之状态模式(State)

    什么是状态? 我们在购物网站进行购物时,订单会产生几种状况:已下单.已付款.送货中.确定收货等状态. 所以系统会判断该订单的状态,不管是哪种状态都应给出对应的操作,这就是状态. 什么是状态模式? 在软 ...

  6. PHP设计模式之状态模式定义与用法详解

    本文实例讲述了PHP设计模式之状态模式定义与用法.分享给大家供大家参考,具体如下: 什么是状态设计模式 当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类. 状态模式主要解决的是当 ...

  7. java设计模式之状态模式_Java中的状态设计模式

    java设计模式之状态模式 在本教程中,我们将探讨另一种流行的行为设计模式-状态设计模式. 当我们使用可以存在于多个状态的对象时,状态设计模式的知识变得非常有用. 当对象的行为取决于其当前状态时,我们 ...

  8. 图解java多线程设计模式 pdf_图解Java设计模式之状态模式

    图解Java设计模式之状态模式 APP抽象活动问题 状态模式基本介绍 状态模式的原理类图 状态模式解决APP抽奖问题 状态模式的注意事项和细节 APP抽象活动问题 请编写程序完成APP抽象活动,具体要 ...

  9. android 状态模式,Android编程设计模式之状态模式详解

    本文实例讲述了Android编程设计模式之状态模式.分享给大家供大家参考,具体如下: 一.介绍 状态模式中的行为是由状态来决定的,不同的状态下有不同的行为.状态模式和策略模式的结构几乎完全一样,但它们 ...

  10. python的out模式_Python设计模式之状态模式

    状态模式 面向对象编程着力于在对象交互时改变它们的状态.在很多问题中,有限状态机(通常名为状态机)是一个非常方便的状态转换建模(并在必要时以数学方式形式化)工具.首先,什么是状态机?状态机是一个抽象机 ...

最新文章

  1. TensorRT-优化-原理
  2. multisim变压器反馈式_变压器的分类及特点
  3. MySQL 获得当前日期时间 函数
  4. 如何在1年内从产品助理到产品高管?
  5. ThreadLocal为什么会内存泄漏(java高级面试)
  6. vue $data data
  7. 面试时被问到「有没有职业规划时」,要怎么回答?
  8. java文件下载以及中文乱码解决
  9. (回文串全排列个数) xiaoxin juju needs help
  10. 免费开源B2C电商系统:(ShopXO无需授权,即可商用)- 入门篇
  11. 国产游戏版号时隔8个月重启 游戏公司董事长喜极而泣
  12. Python必备封装基本代码~Python函数
  13. springboot+vue全栈开发_springboot+vue(一)___开发环境以及前后端项目搭建
  14. 小程序版聊天室|聊天小程序|仿微信聊天界面小程序
  15. webservice 框架比较
  16. 十分钟超简单完成百度地图3.0离线功能
  17. UML各种箭头的含义
  18. 汽车之家和易车该如何走下去?
  19. 再说“恢复被删除的文件”(转)
  20. c语言printf输出整数数字,C语言 念数字 输入一个整数,输出每个数字对应的拼音。当整数为负数时,先输出fu字...

热门文章

  1. 39. PHP 错误与异常处理(3)
  2. Tomcat 连接池的配置
  3. html5中的web worker用法
  4. Remap 后的 USART1 不能发送数据
  5. 《写给大家看的面向对象编程书》读书介绍
  6. 【Python】学习笔记2-数据类型:数组、数组循环切片
  7. 对sppnet网络的理解
  8. git and github secrets
  9. Spring——Java程序员的春天
  10. MEncoder的基础用法—6.10. 保持视频画面比例