Java设计模式(19)状态模式(State模式)
何时使用状态模式
State模式在实际使用中比较多,适合"状态的切换"。因为我们经常会使用If elseif else 进行状态切换, 如果针对状态的这样判断切换反复出现,我们就要联想到是否可以采取State模式了。
不只是根据状态,也有根据属性。如果某个对象的属性不同,对象的行为就不一样,这点在数据库系统中出现频率比较高,我们经常会在一个数据表的尾部,加上property属性含义的字段,用以标识记录中一些特殊性质的记录,这种属性的改变(切换)又是随时可能发生的,就有可能要使用State。
在实际使用,类似开关一样的状态切换是很多的,但有时并不是那么明显,取决于你的经验和对系统的理解深度。
这里要阐述的是"开关切换状态" 和" 一般的状态判断"是有一些区别的," 一般的状态判断"也是有 if..elseif结构,例如:
if (which==1) state="hello";
else if (which==2) state="hi";
else if (which==3) state="bye";
这是一个 " 一般的状态判断",state值的不同是根据which变量来决定的,which和state没有关系。如果改成:
if (state.euqals("bye")) state="hello";
else if (state.euqals("hello")) state="hi";
else if (state.euqals("hi")) state="bye";
这就是 "开关切换状态",是将state的状态从"hello"切换到"hi",再切换到""bye";在切换到"hello",好象一个旋转开关,这种状态改变就可以使用State模式了。
如果单纯有上面一种将"hello"-->"hi"-->"bye"-->"hello"这一个方向切换,也不一定需要使用State模式,因为State模式会建立很多子类,复杂化,但是如果又发生另外一个行为:将上面的切换方向反过来切换,或者需要任意切换,就需要State了。
请看下例:
public class Context{
private Color state=null;
public void push(){
//如果当前red状态 就切换到blue
if (state==Color.red) state=Color.blue;
//如果当前blue状态 就切换到green
else if (state==Color.blue) state=Color.green;
//如果当前black状态 就切换到red
else if (state==Color.black) state=Color.red;
//如果当前green状态 就切换到black
else if (state==Color.green) state=Color.black;
Sample sample=new Sample(state);
sample.operate();
}
public void pull(){
//与push状态切换正好相反
if (state==Color.green) state=Color.blue;
else if (state==Color.black) state=Color.green;
else if (state==Color.blue) state=Color.red;
else if (state==Color.red) state=Color.black;
Sample2 sample2=new Sample2(state);
sample2.operate();
}
}
在上例中,我们有两个动作push推和pull拉,这两个开关动作,改变了Context颜色,至此,我们就需要使用State模式优化它。
另外注意:但就上例,state的变化,只是简单的颜色赋值,这个具体行为是很简单的,State适合巨大的具体行为,因此在,就本例,实际使用中也不一定非要使用State模式,这会增加子类的数目,简单的变复杂。
例如:银行帐户,经常会在Open 状态和Close状态间转换。
例如:经典的TcpConnection,Tcp的状态有创建 侦听 关闭三个,并且反复转换,其创建 侦听 关闭的具体行为不是简单一两句就能完成的,适合使用State。
例如:信箱POP帐号,会有四种状态,start HaveUsername Authorized quit,每个状态对应的行为应该是比较大的,适合使用State。
例如:在工具箱挑选不同工具,可以看成在不同工具中切换,适合使用State。如 具体绘图程序,用户可以选择不同工具绘制方框 直线 曲线,这种状态切换可以使用State。
如何使用状态模式
State需要两种类型实体参与:
- state manager 状态管理器,就是开关,如上面例子的Context实际就是一个state manager,在state manager中有对状态的切换动作。
- 用抽象类或接口实现的父类,不同状态就是继承这个父类的不同子类。
以上面的Context为例,我们要修改它,建立两个类型的实体。
第一步,首先建立一个父类:
public abstract class State{
public abstract void handlepush(Context c);
public abstract void handlepull(Context c);
public abstract void getcolor();
}
父类中的方法要对应state manager中的开关行为,在state manager中 本例就是Context中,有两个开关动作push推和pull拉.那么在状态父类中就要有具体处理这两个动作:handlepush() handlepull();同时还需要一个获取push或pull结果的方法getcolor()。
下面是具体子类的实现:
public class BlueState extends State{
public void handlepush(Context c){
//根据push方法"如果是blue状态的切换到green" ;
c.setState(new GreenState());
}
public void handlepull(Context c){
//根据pull方法"如果是blue状态的切换到red" ;
c.setState(new RedState());
}
public abstract void getcolor(){ return (Color.blue)}
}
同样,其他状态的子类实现如blue一样。
第二步,要重新改写State manager 也就是本例的Context:
ublic class Context{
private Sate state=null; //我们将原来的 Color state 改成了新建的State state;
//setState是用来改变state的状态 使用setState实现状态的切换
pulic void setState(State state){
this.state=state;
}
public void push(){
//状态的切换的细节部分,在本例中是颜色的变化,已经封装在子类的handlepush中实现,这里无需关心
state.handlepush(this);
//因为sample要使用state中的一个切换结果,使用getColor()
Sample sample=new Sample(state.getColor());
sample.operate();
}
public void pull(){
state.handlepull(this);
Sample2 sample2=new Sample2(state.getColor());
sample2.operate();
}
}
至此,我们也就实现了State的refactorying过程。
以上只是相当简单的一个实例,在实际应用中,handlepush或handelpull的处理是复杂的。
系列文章:
Java设计模式(5)共享模式/享元模式(Flyweight模式)
Java设计模式(14)责任链模式(Chain of Responsibility模式)
Java设计模式(19)状态模式(State模式)的更多相关文章
- 折腾Java设计模式之状态模式
原文地址 折腾Java设计模式之状态模式 状态模式 在状态模式(State Pattern)中,类的行为是基于它的状态改变的.这种类型的设计模式属于行为型模式.在状态模式中,我们创建表示各种状态的对象 ...
- 设计模式:状态(State)模式
设计模式:状态(State)模式 一.前言 状态模式在某些场合中使用是非常方便的,什么叫做状态,如果大家学过<编译原理>就会明白DFA M和NFA M,在确定有限状态机和非确定有限 ...
- Java设计模式(22)命令模式(Command模式)
Command模式是最让我疑惑的一个模式,我在阅读了很多代码后,才感觉隐约掌握其大概原理,我认为理解设计模式最主要是掌握起原理构造,这样才对自己实际编程有指导作用.Command模式实际上不是个很具体 ...
- Java设计模式(21)访问模式(Visitor者模式)
Visitor定义:作用于某个对象群中各个对象的操作.它可以使你在不改变这些对象本身的情况下,定义作用于这些对象的新操作. 在Java中,Visitor模式实际上是分离了collection结构中的元 ...
- Java设计模式(18)策略模式(Strategy模式)
Strategy是属于设计模式中 对象行为型模式,主要是定义一系列的算法,把这些算法一个个封装成单独的类. Stratrgy应用比较广泛,比如,公司经营业务变化图,可能有两种实现方式,一个是线条曲线, ...
- Java设计模式(17)解释器模式(Interpreter模式)
Interpreter定义:定义语言的文法,并且建立一个解释器来解释该语言中的句子. Interpreter似乎使用面不是很广,它描述了一个语言解释器是如何构成的,在实际应用中,我们可能很少去构造一个 ...
- Java设计模式(16)中介模式(Mediator模式)
Mediator定义:用一个中介对象来封装一系列关于对象交互行为. 为何使用Mediator模式/中介模式 各个对象之间的交互操作非常多,每个对象的行为操作都依赖彼此对方,修改一个对象的行为,同时会涉 ...
- Java设计模式(15)备忘录模式(Memento模式)
Memento定义:memento是一个保存另外一个对象内部状态拷贝的对象,这样以后就可以将该对象恢复到原先保存的状态. Memento模式相对也比较好理解,我们看下列代码: public class ...
- Java设计模式(13)模板模式(Template模式)
Template模式定义:定义一个操作中算法的骨架,将一些步骤的执行延迟到其子类中. 其实Java的抽象类本来就是Template模式,因此使用很普遍.而且很容易理解和使用,我们直接以示例开始: pu ...
- Java设计模式(12)迭代模式(Iterator模式)
上了这么多年学,我发现一个问题,好象老师都很喜欢点名,甚至点名都成了某些老师的嗜好,一日不点名,就饭吃不香,觉睡不好似的,我就觉得很奇怪,你的课要是讲的好,同学又怎么会不来听课呢,殊不知:“误人子弟, ...
随机推荐
- 【问题跟踪】KryoException: java.io.IOException: No space left on device
今天在对LDA进行不同參数训练模型.记录其avglogLikelihood和logPerplexity,以便推断模型训练是否收敛时,产生了一个令人极度崩溃的事儿:程序在辛辛苦苦跑了7.3h后...挂了 ...
- python之celery使用详解一
前段时间需要使用rabbitmq做写缓存,一直使用pika+rabbitmq的组合,pika这个模块虽然可以很直观地操作rabbitmq,但是官方给的例子太简单,对其底层原理了解又不是很深,遇到很多坑 ...
- nginx 404 403等错误信息页面重定向到网站首页或其它事先指定的页面
server { listen 80; server_name www.espressos.cn; location / { root html/www; index index.html index ...
- Flink源码分析
http://vinoyang.com/ http://wuchong.me Apache Flink源码解析之stream-source https://yq.aliyun.com/articles ...
- [SQL in Azure] Provisioning a SQL Server Virtual Machine on Azure
http://azure.microsoft.com/en-us/documentation/articles/virtual-machines-provision-sql-server/ Provi ...
- shell格式化字符串
假如你有以下代码: TEMP_SQL="SELECT count(uid) from ${TABLE_PREFIX}_%s;" SUM= for((i=${MIN};i<${ ...
- 【转】关于 SELECT /*!40001 SQL_NO_CACHE */ * FROM 的解惑
由于 在数据库做了缓存,在对数据库做了备份,然后在慢查询日志中发现了这一串字符: SELECT /*!40001 SQL_NO_CACHE */ * FROM 上网查了一下,发现好多答案,好多人说的都 ...
- H3C AP实现定时重启
#job radio_diable view system time 1 repeating at 03:00 command wlan radio disable all time 2 rep ...
- error LNK2005: _DllMain@12 已经在 MSVCRTD.lib(dllmain.obj) 中定义
备注:我上次遇到这个问题是Win32 DLL项目中无意中include了afxwin.h,这个是MFC的头文件,把这个include删掉就解决了 ================ 转自:http:// ...
- django 中多字段主键(复合、联合主键)
django中不支持双主键.多主键. 要实现类似功能可以: classMeta: unique_together=(("driver","restaurant" ...