状态模式,又称状态对象模式,状态模式是对象那个的行为模式。状态模式允许一个对象在其内部状态改变的时候改变其行为。
在什么情况下使用状态模式?
1 一个对象的行为依赖于它所处的状态,对象的行为必须随着其状态的改变而改变。
2 对象在某个方法里依赖于一冲或多重的条件转移语句,其中有大量的代码。状态模式把条件转移语句的每一个分支都包装到一个单独的类里。这使得这些条件转移分支能够以类的方式独立了存在和演化。维护这些独立的类也就不再影响到系统的其他部分。
先来看看一个例子===================================================================================================================================
曾侯乙编钟
package com.hh.state.曾侯乙编钟;
public interface 钟 {
public void 打击();
}
package com.hh.state.曾侯乙编钟;
public class 钟A implements 钟 {
@Override
public void 打击() {
// 钟A打击所发出的声音
}
}
package com.hh.state.曾侯乙编钟;
public class 钟B implements 钟 {
@Override
public void 打击() {
// 钟B打击所发出的声音
}
}
package com.hh.state.曾侯乙编钟;
public class 钟C implements 钟 {
@Override
public void 打击() {
// 钟C打击所发出的声音
}
}
package com.hh.state.曾侯乙编钟;
public class 曾侯乙编钟 {
private 钟 state;
public void 打击() {
state.打击();
}
public void setState(钟 state) {
this.state = state;
}
}
在本例中,钟接口所代表的是行为,而曾侯乙类中的钟代表的是状态,意思是状态的改变而造成的行为的改变
谁来定义状态的变化?
状态模式并没有规定哪一个角色决定状态发生转换的条件。如果转换条件是固定的,那么决定就应当由 Context 角色来做。以编钟为例,如果编钟要演奏的曲子是固定的,那么就可以把曲子存储到编钟里,由编钟自己演奏,决定所发出的音的转换。
然而,如果让 State 子类自行决定它的下一任继任者是谁,以及在什么时候进行转换,就更有灵活性。仍然以编钟为例,可以把程序存储在每一个钟里,由每一个中自行决定下面该发生的钟是哪一个,以及谁在什么时候发生,这样就更有灵活性。
或者,由外界时间来决定状态的转换。也就是说,把编钟的演奏交给系统外部的演奏师。
状态对象的创立和湮灭,其中值得权衡的做法有两种:
1 动态地创立所需要的状态对象,不要创立不需要的状态对象。当不再需要某一个状态对象时,便马上把此状态对象那个的示例湮灭掉。这相当于在需要某一个钟时,才把这只钟挂在编钟上;当这只钟使用完后,就立即把它卸下来;当再次使用时,再把它挂回去。这对编钟来说不是一个好主意,因为把那些很沉的编钟搬上搬下是在不方便。但是对于其他的一些系统,在事先不知道要使用哪一个状态对象,而一旦开始使用便不再频繁变更的情况下,这显然是一个好主意。
2 事先创立所有的对象,然后不再湮灭它们。这相当于把事先说的钟都挂在编钟上,然后在演奏过程当中并不把它们卸下来。这显然适用于状态变化比较快和频繁、加载这些状态对象的成本较高的情况,比如编钟系统。
对于Java系统,湮灭一个对象不是由程序完全控制的。当一个对象不再被引用时,Java语言的垃圾处理器会自动把它湮灭掉。但是具体在什么时候湮灭,则是不可以控制的,甚至不是可以预料的。
状态模式的效果
1 状态模式需要对每一个系统可能取得的状态创立一个状态类(State)的子类。当系统的状态变化时,系统便改变所选的子类。所有与一个特定的状态有关的行为都被包装到一个特定的对象里面,使得行为的定义局域化。因为同样的原因,如果有新的状态以它对应的行为需要定义时,可以很方便地通过设立新的子类的方式加到系统里,不需要动其他的类。
2 由于每一个状态都被包装到了类里面,就可以不必采用过程性的(procedural)处理方式,使用长篇累牍的条件转移语句。
3 使用状态模式使系统状态的变化变得明显。由于不用一些属性(内部变量)来致命系统所处的状态,因此,就不用担心修改这些属性不当而造成的错误。
4 可以在系统的不同部分使用相同的一些状态类的对象。这种共享对象的办法是与享元模式相符合的。事实上,此时这些状态对象基本上是只有行为而没有内部状态的享元模式。
5 状态模式的缺点是会造成大量的小的状态类;优点是使程序免于大量的条件转移语句,使程序实际更易于维护。
6 系统所选的状态子类均是从一个抽象状态类或接口继承而来,Java语言的特性使得在Java语言中使用状态模式较为安全。多态性原则是状态模式的核心。
状态模式与策略模式的区别?
状态模式经常与策略模式相混淆。有的时候很难区分应当使用状态模式还是应当使用策略模式。
这个时候,一个简单的方法便是考察环境角色是否有明显的状态和状态的过渡。如果环境角色只有一个状态,那么就应当使用策略模式。策略模式的特点是:一旦环境角色选择了一个具体策略类,那么在整个环境类的生命周期里他都不会改变这个具体策略类。而状态模式则适用于另一种情况,即环境角色有明显的状态转移。在环境类的生命周期里,会有几个不同的状态对象被使用。
本文来自《Java与模式》,为本人学习所用