1、模式简介

状态模式的定义:

  状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。这个模式将状态封装成独立的类,并将动作委托到代表当前状态的类的对象。

状态模式的优点:

  • 封装了转换规则;
  • 枚举可能的状态,在枚举状态之前需要确定状态种类;
  • 将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为;
  • 允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块;
  • 可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。

状态模式的缺点:

  • 状态模式的使用必然会增加系统类和对象的个数;
  • 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱;
  • 状态模式对"开闭原则"的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。

状态模式的适用场景:

  • 当行为需要随着状态的改变而改变时;
  • 当条件、分支语句很复杂冗长而需要优化时。

状态模式和策略模式:

  • 状态模式和策略模式的相同点是它们都需要根据需求选择相应的状态或策略;
  • 状态模式和策略模式的不同点是状态模式是在一个类中通过不同的动作切换不同的状态,而策略模式是为一个类选择某个策略,即状态模式中的Context是和多个状态关联的,而策略模式中的Context只和一个策略关联。

2、案例

  在这个例子中,我们要实现一个糖果机的功能:

  投入一元钱,转动摇把,就可以得到一颗糖果(当然是在及其中还有糖果的情况下);有10%的概率能够得到两颗糖果(被称为Winner)。具体代码如下:

  状态接口State中的代码:

public interface State {
// 投入一元钱
void onMoneyInserted(); // 将钱退回
void onMoneyReturned(); // 转动摇把
void onCrankTurned(); // 给出糖果
void onCandyPoped();
}

  没有投币的状态NoMoneyState中的代码:

public class NoMoneyState implements State {
private CandyMachine candyMachine; public NoMoneyState(CandyMachine candyMachine) {
this.candyMachine = candyMachine;
} @Override
public void onMoneyInserted() {
System.out.println("投币成功!");
candyMachine.setState(candyMachine.getMoneyInsertedState());
} @Override
public void onMoneyReturned() {
System.out.println("还没有投币!操作无效!");
} @Override
public void onCrankTurned() {
System.out.println("还没有投币!操作无效!");
} @Override
public void onCandyPoped() {
System.out.println("还没有投币!操作无效!");
}
}

  投币后的状态MoneyInsertedState中的代码:

public class MoneyInsertedState implements State {
private CandyMachine candyMachine; public MoneyInsertedState(CandyMachine candyMachine) {
this.candyMachine = candyMachine;
} @Override
public void onMoneyInserted() {
System.out.println("不能多次投币!");
} @Override
public void onMoneyReturned() {
System.out.println("正在退钱......退钱成功!");
candyMachine.setState(candyMachine.getNoMoneyState());
} @Override
public void onCrankTurned() {
System.out.println("转动了摇把......");
int random = (int) (Math.random() * 10000);
if (random % 10 == 0 && candyMachine.getCandyCount() > 1) {
System.out.println("恭喜您获得了两颗糖果!");
candyMachine.setState(candyMachine.getWinnerState());
candyMachine.popCandy();
} else {
if (candyMachine.getCandyCount() > 0) {
candyMachine.setState(candyMachine.getCandyPoppingState());
candyMachine.popCandy();
} else {
candyMachine.setState(candyMachine.getNoCandyState());
candyMachine.popCandy();
}
}
} @Override
public void onCandyPoped() {
System.out.println("请先转动摇把!");
}
}

  没有糖果的状态NoCandyState中的代码:

public class noCandyState implements State {
private CandyMachine candyMachine; public noCandyState(CandyMachine candyMachine) {
this.candyMachine = candyMachine;
} @Override
public void onMoneyInserted() {
System.out.println("已经没有糖果了!");
onMoneyReturned();
} @Override
public void onMoneyReturned() {
System.out.println("投币退回!");
candyMachine.setState(candyMachine.getNoMoneyState());
} @Override
public void onCrankTurned() {
System.out.println("已经没有糖果了!操作无效");
onMoneyReturned();
} @Override
public void onCandyPoped() {
System.out.println("已经没有糖果了!");
onMoneyReturned();
}
}

  正在发放糖果的状态CandyPoppingState中的代码:

public class CandyPoppingState implements State {
private CandyMachine candyMachine; public CandyPoppingState(CandyMachine candyMachine) {
this.candyMachine = candyMachine;
} @Override
public void onMoneyInserted() {
System.out.println("正在发放糖果,请勿操作!");
} @Override
public void onMoneyReturned() {
System.out.println("正在发放糖果,请勿操作!");
} @Override
public void onCrankTurned() {
System.out.println("正在发放糖果,请勿操作!");
} @Override
public void onCandyPoped() {
candyMachine.setCandyCount(candyMachine.getCandyCount() - 1);
System.out.println("成功发放了一颗糖果!");
candyMachine.setState(candyMachine.getNoMoneyState());
}
}

  获得两颗糖果的状态WinnerState中的代码:

public class WinnerState implements State {
private CandyMachine candyMachine; public WinnerState(CandyMachine candyMachine) {
this.candyMachine = candyMachine;
} @Override
public void onMoneyInserted() {
System.out.println("正在处理,请勿操作!");
} @Override
public void onMoneyReturned() {
System.out.println("正在处理,请勿操作!");
} @Override
public void onCrankTurned() {
System.out.println("正在处理,请勿操作!");
} @Override
public void onCandyPoped() {
candyMachine.setCandyCount(candyMachine.getCandyCount() - 2);
System.out.println("正在发放第一颗糖果......");
System.out.println("正在发放第二颗糖果......");
System.out.println("糖果发放成功!");
candyMachine.setState(candyMachine.getNoMoneyState());
}
}

  糖果机类CandyMachine中的代码:

public class CandyMachine {
private State moneyInsertedState;
private State noMoneyState;
private State noCandyState;
private State candyPoppingState;
private State winnerState; private State state;
private int candyCount; public CandyMachine(int candyCount) {
this.moneyInsertedState = new MoneyInsertedState(this);
this.noMoneyState = new NoMoneyState(this);
this.noCandyState = new noCandyState(this);
this.candyPoppingState = new CandyPoppingState(this);
this.winnerState = new WinnerState(this);
this.state = noMoneyState;
this.candyCount = candyCount;
} // 投币
public void insertMoney() {
this.state.onMoneyInserted();
} // 退钱
public void returnMoney() {
this.state.onMoneyReturned();
} // 转动摇把
public void turnCrank() {
this.state.onCrankTurned();
} // 发放糖果
public void popCandy() {
this.state.onCandyPoped();
} public State getMoneyInsertedState() {
return moneyInsertedState;
} public void setMoneyInsertedState(State moneyInsertedState) {
this.moneyInsertedState = moneyInsertedState;
} public State getNoMoneyState() {
return noMoneyState;
} public void setNoMoneyState(State noMoneyState) {
this.noMoneyState = noMoneyState;
} public State getNoCandyState() {
return noCandyState;
} public void setNoCandyState(State noCandyState) {
this.noCandyState = noCandyState;
} public State getCandyPoppingState() {
return candyPoppingState;
} public void setCandyPoppingState(State candyPoppingState) {
this.candyPoppingState = candyPoppingState;
} public State getWinnerState() {
return winnerState;
} public void setWinnerState(State winnerState) {
this.winnerState = winnerState;
} public State getState() {
return state;
} public void setState(State state) {
this.state = state;
} public int getCandyCount() {
return candyCount;
} public void setCandyCount(int candyCount) {
this.candyCount = candyCount;
}
}

  测试类Test中的代码:

public class Test {
public static void main(String[] args) {
CandyMachine candyMachine = new CandyMachine(5); candyMachine.insertMoney();
candyMachine.turnCrank(); candyMachine.insertMoney();
candyMachine.turnCrank(); candyMachine.insertMoney();
candyMachine.turnCrank(); candyMachine.insertMoney();
candyMachine.turnCrank(); candyMachine.insertMoney();
candyMachine.turnCrank(); candyMachine.insertMoney();
candyMachine.turnCrank();
}
}

  运行结果如下图所示(左图是每次都获得一颗糖果的情况;右图是有一次获得了两颗糖果的情况):

                                           

  最后贴出状态模式的GitHub代码地址:【GitHub - State】

【设计模式 - 20】之状态模式(State)的更多相关文章

  1. [设计模式-行为型]状态模式(State)

    一句话 在一个类的对象中维护状态的类的对象 概括

  2. 《JAVA设计模式》之状态模式(State)

    在阎宏博士的<JAVA与模式>一书中开头是这样描述状态(State)模式的: 状态模式,又称状态对象模式(Pattern of Objects for States),状态模式是对象的行为 ...

  3. 第20章 状态模式(State Pattern)

    原文 第20章 状态模式(State Pattern) 状态模式  概述:   当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类. 状态模式主要解决的是当控制一个对象状态的条件表 ...

  4. 状态模式(State)-设计模式

    软件模式是将模式的一般概念应用于软件开发领域,即软件开发的 总体指导思路或参照样板.软件模式并非仅限于设计模式,还包括 架构模式.分析模式和过程模式等,实际上,在软件生存期的每一个阶段都存在着一些被认 ...

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

     状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类.当控制一个对象的状态转换条件分支语句(if...else或switch...case)过于复杂时,可以此模式将状态的判断逻辑 ...

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

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

  7. 设计模式 ( 十七) 状态模式State(对象行为型)

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

  8. 乐在其中设计模式(C#) - 状态模式(State Pattern)

    原文:乐在其中设计模式(C#) - 状态模式(State Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 状态模式(State Pattern) 作者:webabcd 介绍 允 ...

  9. 北风设计模式课程---状态模式State(对象行为型)

    北风设计模式课程---状态模式State(对象行为型) 一.总结 一句话总结: 状态模式 具体状态的行为在具体的状态类中就解决,不用交给外部做判断.实质是将多条件判断弄成了多个类,在不同的类中做判断 ...

  10. 二十四种设计模式:状态模式(State Pattern)

    状态模式(State Pattern) 介绍允许一个对象在其内部状态改变时改变它的行为.对象看起来似乎修改了它所属的类. 示例有一个Message实体类,对它的操作有Insert()和Get()方法, ...

随机推荐

  1. mysql5.5提示Deprecated: mysql_query(): The mysql extension is deprecated

    解决方法1:在php程序代码里面设置报警级别 <?php error_reporting = E_ALL & ~E_DEPRECATED 方法2:禁止php报错 display_erro ...

  2. predis如何实现phpredis的pconnect方法

    predis和phpredis都是redis的php客户端,区别可以看这里,这里不赘述. phpredis是php扩展,由C语言编写,诞生较早,很多PHPer都熟悉. predis是用PHP语言编写, ...

  3. 用Django搭建个人博客—(2)

    今日任务: 1 blog的数据库模型定义 2 简单的注册登录功能的实现 项目的源文件已经推送到git@oschina.net. 所以,如果想要参阅源码的请移步 (Fork) http://git.os ...

  4. iOS: 学习笔记, Swift与C指针交互(译)

    Swift与C指针交互 Objective-C和C API经常需要使用指针. 在设计上, Swift数据类型可以自然的与基于指针的Cocoa API一起工作, Swift自动处理几种常用的指针参数. ...

  5. JS获取终端屏幕、浏览窗口的相关信息

    查看终端屏幕相关信息,在windows系统的控制面板可以查到分辨率且可以设置,更具体的浏览器可视窗口等信息则需要借助其他工具.而在程序里需要动态获取时该怎么做呢? 琢磨的一个js方法,供大家参考.如下 ...

  6. LightOj_1284 Lights inside 3D Grid

    题目链接 题意: 给一个X * Y * Z 的立方体, 每个单位立方体内都有一盏灯, 初始状态是灭的, 你每次操作如下: 1)选择一个点(x1, y1, z1)     再选择一个点(x2, y2, ...

  7. Learning LexRank——Graph-based Centrality as Salience in Text Summarization(一)

    (1)What is Sentence Centrality and Centroid-based Summarization ? Extractive summarization works by ...

  8. c# 函数注释 显示换行 ,

    格式:<para>………..</para> /// <summary> /// <para>把html中的随机汉字转换为图片 调用如下:</par ...

  9. [BZOJ 1112] [POI2008] 砖块Klo 【区间K大】

    题目链接:BZOJ - 1112 题目分析 枚举每一个长度为k的连续区间,求出这个区间的最优答案,更新全局答案. 可以发现,这个区间的所有柱子最终都变成这k个数的中位数时最优,那么我们就需要查询这个区 ...

  10. socket.io发送给指定的客户端

    http://www.cnblogs.com/ajccom/archive/2013/07/18/3197809.html http://stackoverflow.com/questions/100 ...