JAVA设计模式:状态模式
声明:转载请说明来源:http://www.cnblogs.com/pony1223/p/7518226.html
一、引出状态模式
假设我们现在有一个糖果机项目,那么我们知道正常一般糖果机提供给用户的行为有这么几种:投入硬币、转动曲柄、退出硬币几种行为;那么糖果机呢一般有这几中状态,待机状态、持有硬币的准备状态、运行状态即正在售出状态和初始状态 这么几种正常状态。 我们发现处于不同状态的时候,持有的行为是不一样的,图如下:
如果我们采用传统的方法来写代码,那么在投入硬币这个行为操作的时候,我们会进行状态的判断,只有在处于待机状态情况下这种行为是正常的,而其他则非正常,那么其他行为也一样,都需要去先判断下当前的状态来进行操作。得到的代码则为:
package study.designmode.statemode; public class CandyMachine { final static int SoldOutState = 0; //初始状态
final static int OnReadyState = 1; //待机状态
final static int HasCoin = 2; //准备状态
final static int SoldState = 3; //售出状态 private int state = SoldOutState; //变量,用于存放当前的状态值
private int count = 0; //糖果的数目 public CandyMachine(int count) {
this.count = count;
if (count > 0) {
state = OnReadyState;
}
} //投入硬币行为的时候,通过判断当前的状态来匹配所有的状态.
public void insertCoin() {
switch (state) {
case SoldOutState:
System.out.println("you can't insert coin,the machine sold out!");
break;
case OnReadyState: //只有在待机状态的时候,投入硬币行为正确,并将状态改变为准备状态
state = HasCoin;
System.out
.println("you have inserted a coin,next,please turn crank!");
break;
case HasCoin:
System.out.println("you can't insert another coin!"); break;
case SoldState:
System.out.println("please wait!we are giving you a candy!"); break;
} } //回退硬币
public void returnCoin() {
switch (state) {
case SoldOutState:
System.out
.println("you can't return,you haven't inserted a coin yet!");
break;
case OnReadyState:
System.out.println("you haven't inserted a coin yet!");
break;
case HasCoin: System.out.println("coin return!");
state = OnReadyState; break;
case SoldState:
System.out.println("sorry,you already have turned the crank!"); break;
} } //转动曲柄
public void turnCrank() {
switch (state) {
case SoldOutState:
System.out.println("you turned,but there are no candies!");
break;
case OnReadyState:
System.out.println("you turned,but you haven't inserted a coin!");
break;
case HasCoin:
System.out.println("crank turn...!");
state = SoldState;
dispense();
break;
case SoldState:
System.out
.println("we are giving you a candy,turning another get nothing,!");
break;
} } //触发发放糖果行为
private void dispense() {
count = count - 1;
System.out.println("a candy rolling out!");
if (count > 0) {
state = OnReadyState;
} else {
System.out.println("Oo,out of candies");
state = SoldOutState;
} } public void printstate() { switch (state) {
case SoldOutState:
System.out.println("***SoldOutState***");
break;
case OnReadyState:
System.out.println("***OnReadyState***");
break;
case HasCoin: System.out.println("***HasCoin***"); break;
case SoldState:
System.out.println("***SoldState***");
break;
} }
}
那么上面这种方式存在什么问题呢?首先很直观的感受就是:
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 设计模式 状态模式
用途 状态模式 (State) 当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类. 状态模式是一种行为型模式. 结构
- java设计模式---状态模式
在阎宏博士的<JAVA与模式>一书中开头是这样描述状态(State)模式的: 状态模式,又称状态对象模式(Pattern of Objects for States),状态模式是对象的行为 ...
- Java设计模式—状态模式
状态模式又是一个比较难的设计模式 定义如下: 当一个对象内在状态改变时允许其改变行为,这个对象看起来像改变了其类. 个人理解:通俗的讲,状态模式就是状态的改变引起了行为的改变,但是,我们只能看到行为的 ...
- Java设计模式-状态模式(State)
核心思想就是:当对象的状态改变时,同时改变其行为,很好理解!就拿QQ来说,有几种状态,在线.隐身.忙碌等,每个状态对应不同的操作,而且你的好友也能看到你的状态,所以,状态模式就两点:1.可以通过改变状 ...
- 14. 星际争霸之php设计模式--状态模式
题记==============================================================================本php设计模式专辑来源于博客(jymo ...
- Java设计模式——组合模式
JAVA 设计模式 组合模式 用途 组合模式 (Component) 将对象组合成树形结构以表示“部分-整体”的层次结构.组合模式使得用户对单个对象和组合对象的使用具有唯一性. 组合模式是一种结构型模 ...
- java设计模式--单列模式
java设计模式--单列模式 单列模式定义:确保一个类只有一个实例,并提供一个全局访问点. 下面是几种实现单列模式的Demo,每个Demo都有自己的优缺点: Demo1: /** * 单列模式需要满足 ...
- 3.java设计模式-建造者模式
Java设计模式-建造者模式 在<JAVA与模式>一书中开头是这样描述建造(Builder)模式的: 建造模式是对象的创建模式.建造模式可以将一个产品的内部表象(internal repr ...
- Java设计模式-代理模式之动态代理(附源代码分析)
Java设计模式-代理模式之动态代理(附源代码分析) 动态代理概念及类图 上一篇中介绍了静态代理,动态代理跟静态代理一个最大的差别就是:动态代理是在执行时刻动态的创建出代理类及其对象. 上篇中的静态代 ...
- Java设计模式——外观模式
JAVA 设计模式 外观模式 用途 外观模式 (Facade) 为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用. 外观模式是一种结构型模式. 结构
随机推荐
- Python之系统交互(subprocess)
本节内容 os与commands模块 subprocess模块 subprocess.Popen类 总结 我们几乎可以在任何操作系统上通过命令行指令与操作系统进行交互,比如Linux平台下的shell ...
- 如何自己写一个公用的NPM包
以markdown-clear,创建过程为例,讲解整个NPM包创建和发布流程 1 如何创建一个包 1.1 创建并使用一个工程 在GitHub上新建一个仓库,其名markdown-clear clone ...
- 在Mac OS 下 build Tesseract4.0 源码并在命令行中使用
作者电脑:Mac Mini 系统信息:OS X EI Capitan 10.11.6 Tesseract4.0github地址:https://github.com/tesseract-ocr/tes ...
- Ubuntu超好用软件:markdown编辑器
Ubuntu上好用的markdown编辑器:typora 安装教程: sudo add-apt-repository ppa:hzwhuang/ss-qt5 sudo apt-get update s ...
- 关于无法使用python执行进入百度页面的代码修改
前几天听了个坑爹的视频教学,按照你们的方法做了,但尼玛,执行下来各种问题啊: 首先进入页面,总是提示开发者模式,删了下次执行又挂了,于是乎我就找网上帖子解决问题,果然被我解决了 先装这两个文件,把浏览 ...
- SQL Server数据库基础笔记
启动和停止SQL Server服务三种形式 后台启动服务 计算机->右键->管理->服务和应用程序->服务->sql server(MSSQLSERVER) SQL Se ...
- SSE图像算法优化系列十:简单的一个肤色检测算法的SSE优化。
在很多场合需要高效率的肤色检测代码,本人常用的一个C++版本的代码如下所示: void IM_GetRoughSkinRegion(unsigned char *Src, unsigned char ...
- 扩展Python模块系列(二)----一个简单的例子
本节使用一个简单的例子引出Python C/C++ API的详细使用方法.针对的是CPython的解释器. 目标:创建一个Python内建模块test,提供一个功能函数distance, 计算空间中两 ...
- Markdown学习笔记(一) 基本的Markdown标签
Markdown是一种可以使用普通文本编辑器编写的标记语言,通过简单的标记语法,它可以使普通文本内容具有一定的格式. Markdown的语法简洁明了.学习容易,而且功能比纯文本更强,因此有很多人用它写 ...
- Failed resolution of: Landroid/support/v7/internal/widget/TintManager;
碰到这个问题,一般都是build.gradle中导入的包不匹配的问题,如TabLayout与ViewPager搭配使用的时候,必须保持导入包的版本一致 compile 'com.android.sup ...