设计模式-状态模式
来源:互联网 发布:蔡仕伟淘宝 编辑:程序博客网 时间:2024/06/05 22:56
模式动机
在很多情况下,一个对象的行为取决于一个或多个动态变化的属性,这样的属性叫做状态,这样的对象叫做有状态的(stateful)对象,这样的对象状态是从事先定义好的一系列值中取出的。当一个这样的对象与外部事件产生互动时,其内部状态就会改变,从而使得系统的行为也随之发生变化。
在UML中可以使用状态图来描述对象状态的变化。
模式定义
状态模式(State Pattern) :允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。其别名为状态对象(Objects for States),状态模式是一种对象行为型模式。
状态模式所涉及到的角色
● 环境(Context)角色,也成上下文:定义客户端所感兴趣的接口,并且保留一个具体状态类的实例。这个具体状态类的实例给出此环境对象的现有状态。
● 抽象状态(State)角色:定义一个接口,用以封装环境(Context)对象的一个特定的状态所对应的行为。
● 具体状态(ConcreteState)角色:每一个具体状态类都实现了环境(Context)的一个状态所对应的行为。
uml
具体例子:
策略模式和状态模式是双胞胎,在出生时才分开。你已经知道,策略模式是围绕可以互换的算法来创建成功业务的,然而,状态走的是更崇高的路,它通过改变对象内部的状态来帮助对象控制自己的行为。
题例:
万能糖果公司 我们认为糖果机的控制器需要如下图般的工作,希望你能用Java语言帮我们实现它,而且需要让设计能够尽量有弹性而且好维护,因为将来我们可能要为它增加更多的行为。
没错上图是一个状态图。
1:首先找出所有的状态:“没有25分钱”,“有25分钱”,“糖果售罄”,“售出糖果”。
2:接下来,创建一个实例变量来持有目前的状态,然后定义每个状态的值: 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;
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;
3:现在,我们将所有系统中可以发生的动作整合起来: “投入25分钱”,“退回25分钱”,“转动曲柄”,“发放糖果” 这些动作是糖果机的接口,这是你能对糖果机做的事情, 调用任何一个动作都会造成状态的转换, 发放糖果更多是糖果机的内部动作,机器自己调用自己。
4:现在,我们创建了一个类,它的作用就像是一个状态机,第每一个动作,我们都创建了一个对应的方法,这些方法利用条件语句来决定在每个状态内什么行为是恰当的。比如对“投入25分钱”这个动作来说,我们可以把对应方法写成下面的样子:
新的设计
不要维护我们现有的代码,我们重写它以便于将状态对象封装在各自的类中,然后在动作发生时委托给当前状态。
1:首先,我们定义一个State接口,在这个接口内,糖果机的每个动作都有一个对应的方法。
2:然后为机器中的每个状态实现状态类,这些类将负责在对应的状态下进行机器的行为。
3:最后,我们要摆脱旧的条件代码,取而代之的方法是,将动作委托到状态类。 现在我们要把一个状态的所有行为放在一个类中,这么一来我们将行为局部化了,并使得事情更容易改变和理解。
定义状态接口和类 我们先完成第一个版本的糖果机的重新实现之后,再回来处理添加“赢家”的修改。 首先让我们创建一个State接口,所有的状态都必须实现这个接口:
interface State{ void insertQuarter(); void ejectQuarter(); void turnCrank(); void dispense(); }
重新改造糖果机
class GumballMachine_ { State soldOutState; State noQuarterState; State hasQuarterState; State soldState; State state = soldState; int count = 0; public GumballMachine_(int count) { soldOutState = new SoldOutState(this); noQuarterState = new NoQuarterState(this); hasQuarterState = new HasQuarterState(this); soldOutState = new SoldState(this); this.count = count; if (count > 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(); if(count!=0){ count=count-1; } } public State getSoldState() { return soldState; } public State getHasQuarterState() { return hasQuarterState; } public State getNoQuarterState() { return noQuarterState; } public State getSoldOutState() { return soldOutState; } }
状态类举例
class HasQuarterState implements State { GumballMachine_ gumballMachine; public HasQuarterState(GumballMachine_ gumballMachine) { this.gumballMachine = gumballMachine; } @Override public void insertQuarter() { System.out.println("这是一个对此状态不恰当的动作"); } @Override public void ejectQuarter() { System.out.println("退出顾客的25分钱,并将状态转换到NoQuarterState状态"); gumballMachine.setState(gumballMachine.getNoQuarterState()); }@Override public void turnCrank() { System.out.println("当曲柄转动,我们将状态转换到SoldState"); gumballMachine.setState(gumballMachine.getSoldState()); }@Override public void dispense() { System.out.println("这是次状态的另一个不恰当动作"); } }
策略模式和状态模式的区别
但是这两个模式的差别在于它们的“意图” 以状态模式而言
我们将一群行为封装在状态对象中,context的行为随时可委托到那些状态对象中的一个,随着时间而流逝,当前状态在状态对象集合中游走改变,以反映出context内部的状态,因此,context的行为也会跟着改变,但是context的客户对于状态对象了解不多,甚至根本是浑然不觉。
而策略模式而言,客户通常主动指定Context所要组合的策略对象时哪一个。现在,固然策略模式让我们具有弹性,能够在运行时改变策略,但对于某个context对象来说,通常都只有一个最适当的策略对象。 一般的,我们把策略模式想成是除了继承之外的一种弹性替代方案,如果你使用继承定义了一个类的行为,你将被这个行为困住,是指要修改它都很难,有了策略模式,你可以通过组合不同的对象来改变行为。
我们把状态模式想成是不用咋icontext中防止旭东条件判断的替代方案,通过将行为包装进状态对象中,你可以通过在context内简单地改变状态对象来改变context的行为。
优点:
封装了转换规则。
枚举可能的状态,在枚举状态之前需要确定状态种类。
将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。
允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。
可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。
缺点:
状态模式的使用必然会增加系统类和对象的个数。
状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。
状态模式对“开闭原则”的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态;而且修改某个状态类的行为也需修改对应类的源代码。
适用环境
对象的行为依赖于它的状态(属性)并且可以根据它的状态改变而改变它的相关行为。
代码中包含大量与对象状态有关的条件语句,这些条件语句的出现,会导致代码的可维护性和灵活性变差,不能方便地增加和删除状态,使客户类与类库之间的耦合增强。在这些条件语句中包含了对象的行为,而且这些条件对应于对象的各种状态。
我的微信二维码如下,欢迎交流讨论
欢迎关注《IT面试题汇总》微信订阅号。每天推送经典面试题和面试心得技巧,都是干货!
微信订阅号二维码如下:
- 设计模式:状态模式
- 设计模式-----状态模式
- 设计模式 状态模式
- 设计模式 - 状态模式
- 设计模式---状态模式
- 设计模式-状态模式
- 设计模式:状态模式
- 设计模式 - 状态模式
- 设计模式-状态模式
- 设计模式--状态模式
- 设计模式-状态模式
- 设计模式:状态模式
- 设计模式-状态模式
- 设计模式-状态模式
- [设计模式]状态模式
- 设计模式 状态模式
- 设计模式--状态模式
- 设计模式--状态模式
- 分布式缓存技术redis学习系列(三)——redis高级应用(主从、事务与锁、持久化)
- listview 中出现的ArrayIndexOutOfBoundsException
- jzoj 4710. 【NOIP2016提高A组模拟8.17】Value 贪心+动态规划
- iOS控件:状态栏
- leetcode-java-110. Balanced Binary Tree
- 设计模式-状态模式
- 验证数学黑洞 ,用户输入一个四位数,输出变换到6174的过程
- 分布式缓存技术redis学习系列(四)——redis高级应用(集群搭建、集群分区原理、集群操作)
- LA 7457 Discrete Logarithm Problem(shank的大步小布算法)
- velociyt判断变量是否为null
- Linux修改默认系统启动级别为命令行模式
- 学编程的都是疯子!!!
- 黄阶低级 - 《 Java 核心》- 4.4 静态域和静态方法 - 修改0次
- 【NOIP2000】单词接龙