转载:http://www.cnblogs.com/pony1223/p/7518226.html

一、引出状态模式

假设我们现在有一个糖果机项目,那么我们知道正常一般糖果机提供给用户的行为有这么几种:投入硬币、转动曲柄、退出硬币几种行为;那么糖果机呢一般有这几中状态,待机状态、持有硬币的准备状态、运行状态即正在售出状态和初始状态 这么几种正常状态。 我们发现处于不同状态的时候,持有的行为是不一样的,图如下:

如果我们采用传统的方法来写代码,那么在投入硬币这个行为操作的时候,我们会进行状态的判断,只有在处于待机状态情况下这种行为是正常的,而其他则非正常,那么其他行为也一样,都需要去先判断下当前的状态来进行操作。得到的代码则为:

1 package study.designmode.statemode;

2

3 public class CandyMachine {

4

5 final static int SoldOutState = 0; //初始状态

6 final static int OnReadyState = 1; //待机状态

7 final static int HasCoin = 2; //准备状态

8 final static int SoldState = 3; //售出状态

9

10 private int state = SoldOutState; //变量,用于存放当前的状态值

11 private int count = 0; //糖果的数目

12

13 public CandyMachine(int count) {

14 this.count = count;

15 if (count > 0) {

16 state = OnReadyState;

17 }

18 }

19

20 //投入硬币行为的时候,通过判断当前的状态来匹配所有的状态.

21 public void insertCoin() {

22 switch (state) {

23 case SoldOutState:

24 System.out.println("you can't insert coin,the machine sold out!");

25 break;

26 case OnReadyState: //只有在待机状态的时候,投入硬币行为正确,并将状态改变为准备状态

27 state = HasCoin;

28 System.out

29 .println("you have inserted a coin,next,please turn crank!");

30 break;

31 case HasCoin:

32 System.out.println("you can't insert another coin!");

33

34 break;

35 case SoldState:

36 System.out.println("please wait!we are giving you a candy!");

37

38 break;

39 }

40

41 }

42

43 //回退硬币

44 public void returnCoin() {

45 switch (state) {

46 case SoldOutState:

47 System.out

48 .println("you can't return,you haven't inserted a coin yet!");

49 break;

50 case OnReadyState:

51 System.out.println("you haven't inserted a coin yet!");

52 break;

53 case HasCoin:

54

55 System.out.println("coin return!");

56 state = OnReadyState;

57

58 break;

59 case SoldState:

60 System.out.println("sorry,you already have turned the crank!");

61

62 break;

63 }

64

65 }

66

67 //转动曲柄

68 public void turnCrank() {

69 switch (state) {

70 case SoldOutState:

71 System.out.println("you turned,but there are no candies!");

72 break;

73 case OnReadyState:

74 System.out.println("you turned,but you haven't inserted a coin!");

75 break;

76 case HasCoin:

77 System.out.println("crank turn...!");

78 state = SoldState;

79 dispense();

80 break;

81 case SoldState:

82 System.out

83 .println("we are giving you a candy,turning another get nothing,!");

84 break;

85 }

86

87 }

88

89 //触发发放糖果行为

90 private void dispense() {

91 count = count - 1;

92 System.out.println("a candy rolling out!");

93 if (count > 0) {

94 state = OnReadyState;

95 } else {

96 System.out.println("Oo,out of candies");

97 state = SoldOutState;

98 }

99

100 }

101

102 public void printstate() {

103

104 switch (state) {

105 case SoldOutState:

106 System.out.println("***SoldOutState***");

107 break;

108 case OnReadyState:

109 System.out.println("***OnReadyState***");

110 break;

111 case HasCoin:

112

113 System.out.println("***HasCoin***");

114

115 break;

116 case SoldState:

117 System.out.println("***SoldState***");

118 break;

119 }

120

121 }

122 }

那么上面这种方式存在什么问题呢?首先很直观的感受就是:

1.存在大量的switch case 语句  当然可以用if  else 也是一样的。

2.可扩展性差,并且一旦要加入一种新的状态,那么就会要修改所有的switch case  不符合开闭原则

3.没有采用面向对象的方式去封装

比如,这个时候,新增加了一种状态,赢家状态,即可以获取到两粒糖果;那么如果用上面的方式,肯定是不符合开闭原则的,同时扩展性也是不好的;那么我们有什么其它的方式来解决呢?

二、解决办法

为了解决上面的问题,我们首先分析项目中变化的部分和不变的部分,抽化出变化的部分,我们发现糖果机提供的行为一般是不变的,就是投入硬币、转动曲柄给、退回硬币、机器发放糖果;而糖果机的状态是可以变化的,可以新增出一种状态来,比如我们说的赢家状态。那么我们这个抽出变化的部分,即我们说的状态,于是出现了下面的结构设计方案:

这个结构图告诉我们,提炼出状态接口出来,然后将各个状态抽出,并去实现接口,每个状态都持有投入硬币,退回硬币,转动曲柄、售出糖果这几种行为对应的方法做出相应;而糖果机持有所有的状态,并通过引用状态接口来操作各个状态;这种设计架构就是我们说的状态模式。

状态模式定义:对象行为的变化是由于状态的变化引入,那么即当内部状态发生变化的时候,就会改变对象的行为,而这种改变视乎就改变了整个类。

那么现在采用状态模式来解决问题:

1.首先定义接口:

package study.designmode.statemode.state;

public interface State {

public void insertCoin();

public void returnCoin();

public void turnCrank();

public void dispense();

public void printstate();

}

2.定义各个状态的实现类

准备状态:

package study.designmode.statemode.state;

import java.util.Random;

public class HasCoin implements State {

private CandyMachine mCandyMachine;

public HasCoin(CandyMachine mCandyMachine) {

this.mCandyMachine = mCandyMachine;

}

@Override

public void insertCoin() {

// TODO Auto-generated method stub

System.out.println("you can't insert another coin!");

}

@Override

public void returnCoin() {

// TODO Auto-generated method stub

System.out.println("coin return!");

mCandyMachine.setState(mCandyMachine.mOnReadyState);

}

@Override

public void turnCrank() {

// TODO Auto-generated method stub

System.out.println("crank turn...!");

Random ranwinner=new Random();

int winner=ranwinner.nextInt(10);

if(winner==0)

{

mCandyMachine.setState(mCandyMachine.mWinnerState);

}else

{

mCandyMachine.setState(mCandyMachine.mSoldState);

}

}

@Override

public void dispense() {

}

@Override

public void printstate() {

// TODO Auto-generated method stub

System.out.println("***HasCoin***");

}

}

说明:我们会发现里面存在一个糖果机的属性,而之所以存在这个属性,就是因为糖果机中持有所有的状态,而在准备状态下,肯定会由于某种行为发生状态改变,而要改变的状态都在糖果机中,所以持有一个糖果机属性,下面也一样,不在重复说明。

准备状态:

package study.designmode.statemode.state;

public class OnReadyState implements State {

private CandyMachine mCandyMachine;

public OnReadyState(CandyMachine mCandyMachine)

{

this.mCandyMachine=mCandyMachine;

}

@Override

public void insertCoin() {

// TODO Auto-generated method stub

System.out

.println("you have inserted a coin,next,please turn crank!");

mCandyMachine.setState(mCandyMachine.mHasCoin);

}

@Override

public void returnCoin() {

// TODO Auto-generated method stub

System.out.println("you haven't inserted a coin yet!");

}

@Override

public void turnCrank() {

// TODO Auto-generated method stub

System.out.println("you turned,but you haven't inserted a coin!");

}

@Override

public void dispense() {

// TODO Auto-generated method stub

}

@Override

public void printstate() {

// TODO Auto-generated method stub

System.out.println("***OnReadyState***");

}

}

初始状态:

package study.designmode.statemode.state;

public class SoldOutState implements State {

private CandyMachine mCandyMachine;

public SoldOutState(CandyMachine mCandyMachine)

{

this.mCandyMachine=mCandyMachine;

}

@Override

public void insertCoin() {

// TODO Auto-generated method stub

System.out.println("you can't insert coin,the machine sold out!");

}

@Override

public void returnCoin() {

// TODO Auto-generated method stub

System.out

.println("you can't return,you haven't inserted a coin yet!");

}

@Override

public void turnCrank() {

// TODO Auto-generated method stub

System.out.println("you turned,but there are no candies!");

}

@Override

public void dispense() {

// TODO Auto-generated method stub

}

@Override

public void printstate() {

// TODO Auto-generated method stub

System.out.println("***SoldOutState***");

}

}

售出状态:

package study.designmode.statemode.state;

public class SoldState implements State {

private CandyMachine mCandyMachine;

public SoldState(CandyMachine mCandyMachine)

{

this.mCandyMachine=mCandyMachine;

}

@Override

public void insertCoin() {

// TODO Auto-generated method stub

System.out.println("please wait!we are giving you a candy!");

}

@Override

public void returnCoin() {

// TODO Auto-generated method stub

System.out.println("you haven't inserted a coin yet!");

}

@Override

public void turnCrank() {

// TODO Auto-generated method stub

System.out

.println("we are giving you a candy,turning another get nothing,!");

}

@Override

public void dispense() {

// TODO Auto-generated method stub

mCandyMachine.releaseCandy();

if (mCandyMachine.getCount() > 0) {

mCandyMachine.setState(mCandyMachine.mOnReadyState);

} else {

System.out.println("Oo,out of candies");

mCandyMachine.setState(mCandyMachine.mSoldOutState);

}

}

@Override

public void printstate() {

// TODO Auto-generated method stub

System.out.println("***SoldState***");

}

}

赢家状态:

package study.designmode.statemode.state;

public class WinnerState implements State {

private CandyMachine mCandyMachine;

public WinnerState(CandyMachine mCandyMachine) {

this.mCandyMachine = mCandyMachine;

}

@Override

public void insertCoin() {

// TODO Auto-generated method stub

System.out.println("please wait!we are giving you a candy!");

}

@Override

public void returnCoin() {

// TODO Auto-generated method stub

System.out.println("you haven't inserted a coin yet!");

}

@Override

public void turnCrank() {

// TODO Auto-generated method stub

System.out

.println("we are giving you a candy,turning another get nothing,!");

}

@Override

public void dispense() {

// TODO Auto-generated method stub

mCandyMachine.releaseCandy();

if (mCandyMachine.getCount() == 0) {

mCandyMachine.setState(mCandyMachine.mSoldOutState);

} else {

System.out.println("you are a winner!you get another candy!");

mCandyMachine.releaseCandy();

if (mCandyMachine.getCount() > 0) {

mCandyMachine.setState(mCandyMachine.mOnReadyState);

} else {

System.out.println("Oo,out of candies");

mCandyMachine.setState(mCandyMachine.mSoldOutState);

}

}

}

@Override

public void printstate() {

// TODO Auto-generated method stub

System.out.println("***WinnerState***");

}

}

3.糖果机,糖果机要持有所有的状态,并在初始化的时候,要设置其开始的状态,然后糖果的各个行为,就委托到了各个状态中自己维护,代码如下:

package study.designmode.statemode.state;

public class CandyMachine {

State mSoldOutState;

State mOnReadyState;

State mHasCoin;

State mSoldState;

State mWinnerState;

private State state;

private int count = 0;

public CandyMachine(int count) {

this.count = count;

mSoldOutState = new SoldOutState(this);

mOnReadyState = new OnReadyState(this);

mHasCoin = new HasCoin(this);

mSoldState = new SoldState(this);

mWinnerState = new WinnerState(this);

if (count > 0) {

state = mOnReadyState;

} else {

state = mSoldOutState;

}

}

public void setState(State state) {

this.state = state;

}

public void insertCoin() {

state.insertCoin();

}

public void returnCoin() {

state.returnCoin();

}

public void turnCrank() {

state.turnCrank();

state.dispense();

}

void releaseCandy() {

// TODO Auto-generated method stub

if (count > 0) {

count = count - 1;

System.out.println("a candy rolling out!");

}

}

public int getCount() {

return count;

}

public void printstate() {

state.printstate();

}

}

4.测试类

package study.designmode.statemode.state;

public class MainTest {

public static void main(String[] args) {

CandyMachine mCandyMachine = new CandyMachine(6);

mCandyMachine.printstate();

mCandyMachine.insertCoin();

mCandyMachine.printstate();

mCandyMachine.turnCrank();

mCandyMachine.printstate();

mCandyMachine.insertCoin();

mCandyMachine.printstate();

mCandyMachine.turnCrank();

mCandyMachine.printstate();

}

}

结果如下:

可以和开始的传统方案对比,结果是一样的,但是具备了可扩展性。

三、总结

通过上面的例子,我们已经对状态模式有所了解,下面我们做一个总结,来回顾我们的状态模式:

1.状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。   理解:这个模式将状态封装成独立的类,并将动作委托到代表当前状态的对象,这就是说行为会随着内部状态而改变。   “看起来好像修改了它的类”是什么意思呢?从客户的视角来看:如果说你使用的对象能够完全改变它的行为,那么你会觉得,这个对象实际上是从别的类实例化而来的。然而,实际上,你知道我们是在使用组合通过简单引用不同的状态对象来造成类改变的假象

2.状态模式要点

(1)客户不会和状态进行交互,全盘了解状态是 context的工作(2)在状态模式中,每个状态通过持有Context的引用,来实现状态转移(3)使用状态模式总是会增加设计中类的数目,这是为了要获得程序可扩展性,弹性的代价,如果你的代码不是一次性的,后期可能会不断加入不同的状态,那么状态模式的设计是绝对值得的。【同时也是一个缺点】(4)状态类可以被多个context实例共享

3.状态模式和策略模式对比

首先让我们来看看它们之间更多的相似之处:添加新的状态或策略都很容易,而且不需要修改使用它们的Context对象。它们都让你的代码符合OCP原则(软件对扩展应该是开发的,对修改应该是关闭的)。在状态模式和策略模式中,Context对象对修改是关闭的,添加新的状态或策略,都不需要修改Context。正如状态模式中的Context会有初始状态一样,策略模式同样有默认策略。状态模式以不同的状态封装不同的行为,而策略模式以不同的策略封装不同的行为。它们都依赖子类去实现相关行为

两个模式的差别在于它们的”意图“不同:

状态模式帮助对象管理状态,我们将一群行为封装早状态对象中,context的行为随时可委托到那些状态中的一个.随着时间的流逝,当前状态在状态对象集合中游走改变,以反映context内部状态,因此,context的行为也会跟着改变。当要添加新的状态时,不需要修改原来代码添加新的状态类即可。 而策略模式允许Client选择不同的行为。通过封装一组相关算法,为Client提供运行时的灵活性。Client可以在运行时,选择任一算法,而不改变使用算法的Context。一些流行的策略模式的例子是写那些使用算法的代码,例如加密算法、压缩算法、排序算法。客户通常主动指定context所要组合的策略对象是哪一个.

一句话:最根本的差异在于策略模式是在求解同一个问题的多种解法,这些不同解法之间毫无关联;状态模式则不同,状态模式要求各个状态之间有所关联,以便实现状态转移。

java 状态设计模式_JAVA设计模式:状态模式相关推荐

  1. java输出不同颜色_Java设计模式-策略模式、状态模式

    推荐阅读: 一只Tom猫:都是"Redis惹的祸",害我差点挂在美团三面,真是"虚惊一场"! java喵:6大面试技能树:JAVA基础+JVM+算法+数据库+计 ...

  2. java外观设计修改_Java设计模式之外观模式和装饰器模式的设计(精选)

    前言 本篇来学习下结构型模式的外观模式和装饰器模式. 外观模式 简介 外观模式隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口.这种类型的设计模式属于结构型模式,它向现有的系统添加一个接 ...

  3. java 设计模式_Java设计模式的常见应用场景

    一.Java I/O中的设计模式 1.适配器模式 适配器模式就是把一个类的接口变换成客户端所能接受的另一种接口,从而使两个接口不匹配而无法在一起工作的两个类能够在一起工作.通常被用在一个项目需要引用一 ...

  4. java装饰模式理解_Java设计模式之装饰模式趣谈

    JVM:"上次给我招的工人不错啊!" oo程序员:"---.." JVM:"现在来我开的博物馆生意越来越好了,原来"舞台剧"的方式 ...

  5. java中组合_java中组合模式详解和使用方法

    组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象.组合模式依据树形结构来组合对象,用来表示部分以及整体层次.这种类型的设计模式属于结构型模式, ...

  6. java状态机设计模式_Java设计模式之状态模式详解

    (本文由言念小文原创,转载请注明出处) 在实际工作中经常遇到某个对象,处于不同的状态有不同行为逻辑.且状态之间可以相互迁移的业务场景,特别是在开发通信协议栈类软件中尤为多见.<设计模式之禅> ...

  7. java工厂方法_Java设计模式之工厂方法模式

    2.工厂方法模式 <设计模式之禅>中用神话故事女娲造人来比概述工厂方法模式. 女娲采集黄土捏成人的形状,然后放到八卦炉中烧制,最后放置到大地上生长,工艺过程是没有错的,但是意外随时都会发生 ...

  8. 格力电器Java面试题_JAVA设计模式学习--工厂模式

    今天谈一下对工厂模式学习的总结. 看完视频和文章之后要自己表述工厂模式,总是感觉无从说起,不知道怎么去定义工厂模式,反复看了几遍之后终于理解一点. 自己理解工厂模式是通过这两种模式的特点来理解和定义的 ...

  9. java 工厂方法_java设计模式-工厂方法模式

    1.工厂方法(FactoryMethod)模式的定义 定义一个创建产品对象的工厂接口,将产品对象的实际创建工作推迟到具体子工厂类当中.这满足创建型模式中所要求的"创建与使用相分离" ...

最新文章

  1. NBIOT-NPSS/NSS/NPBCH的资源位置
  2. python创建列向量_关于Numpy中的行向量和列向量详解
  3. 只因路由器密码太弱,IP被黑客利用发虐童图片,无辜夫妇:我们甚至想自杀...
  4. 上海交通大学乐经良高数手写笔记-一元积分学
  5. ThinkPHP框架整合phpqrcode生成二维码DEMO
  6. 我爱你,与你无关——登录系统的逻辑与结构
  7. mysql8.0.12插件_MySQL8.0.12 安装及配置
  8. php乱码调试,NotePad++ 调试PHP代码中文显示乱码
  9. 超好看的引导购买页源码
  10. 解决Flink案例DataStream中使用keyBy(0),keyBy弃用的问题
  11. 张孝祥《Java就业培训教程》读书笔记
  12. 3道js面试题引发的脑洞
  13. java学习(分布式架构)
  14. Android系统网络架构
  15. Java程序员,你必须得知道并发编程概念
  16. Android 10.0去掉后台启动Service的限制
  17. Oracle EBS 寄销/VMI(1)--基础设置;寄销/VMI(2)--采购篇
  18. 如何0基础学stm32?
  19. PAKDD 2019 中国企业深兰科技夺冠:AutoML 如何推动 AI 应用落地?
  20. Yii Framework 开发教程(41) Zii组件-Tabs示例

热门文章

  1. ios 数字键盘左下角添加按钮_iOS8数字键盘加左下角完成button
  2. 图数据库:AgensGraph
  3. wamp下Apache2.4.x局域网访问403的解决办法
  4. 安装bashee-1-1.2.1.tar.bz2多媒体播放器时的出错问题
  5. time包中Parse和Format的区别
  6. 汉诺塔III HDU - 2064
  7. QT+FFMPEG实现视频播放
  8. 【CI】CN.一种多尺度协同变异的微粒群优化算法
  9. org.hibernate.PersistentObjectException: detached entity passed to persist
  10. 升级到php7和安装拓展(mac centos)