状态模式

来源:互联网 发布:pony淘宝旗舰店叫什么 编辑:程序博客网 时间:2024/04/29 09:55
 
状态模式(State Pattern)
     状态模式又称为状态对象模式,是对象的行为模式。
     状态模式允许一个对象在其内部状态改变时改变其行为。这个对象看上去就像时改变了它的类一样。
     在很多情况下,一个对象的行为取决于一个或多个动态变化的属性,这样的属性叫做状态,这样的对象叫做有状态(stateful)的对象。这样对象的状态是从事先定好的一系列值中取出。当一个这样的对象与外部事件产生互动时,其内部状态就会改变,从而使得系统形象也随之发生改变。
一、状态模式的结构
     状态模式把所研究的对象的行为包装在不同的状态对象里,每一个状态对象都属于一个抽象状态类的子类。状态模式的意图是让一个对象在其内部状态改变的时候,其行为也随之改变。
1、模式所涉及的角色
     (1)抽象状态角色(State):定义一个接口,用以封装环境(Context)对象的一个特定的状态所对应的作为。
     (2)具体状态角色(ConcreteState):每一个具体状态类都实现了环境(Context)的一个状态所对应的行为。
     (3)环境角色(Context):定义客户端所感兴趣的接口,并且保留一个具体状态类的实例。这个具体张状态类的实例给出环境对象的现有状态。
     环境类的某一个行为委派给类型为State的一个对象。由于State本身是一个接口或抽象类,实际担当此任务的是具体状态类。
     通过使用多态性原则,可以动态的改变环境类的属性State的内容,使其从指向一个具体状态类变换到指向另一个具体状态类,从而使环境的行为由不同的具体状态类来执行。
2、源代码
     (1)环境角色:持有一个State对象,并把所有的行为委派给此对象。
public class Context {
    public void sampleOperation(){
        state.sampleOperation();
    }
    public void setState(State state){
            this.state = state;
        }
    private State state;
}
     (2)抽象状态角色
public interface State {
    void sampleOperation();
}
     (3)具体状态角色:实现了接口规定的方法
public class ConcreteState implements State
{
    public void sampleOperation(){}
}
二、状态模式的效果
     状态模式有以下的效果
     (1)状态模式需要对每一个系统可能取得状态创立一个状态类的子类。当系统的状态变化时,系统便改变所选的子类。所有与一个特定的状态有关的作为都被包装到一个特定的对象里面,使得行为的定义局域化。因为同样的原因,如果有新的状态及它对应的行为需要定义时,可以很方便的通过设立新的子类的方式加到系统里。不需要改动其它的类
     (2)由于每一个状态都被包装到了类里面,就可以不必采用过程(procedural)行的处理方式,使用长篇累牍的条件转移语句。
     (3)使用状态模式使系统状态发生很明显的变化。由于不用一些属性(内部变量)来指明系统所处的状态,因此不用担心修改这些属性不当而造成的错误。
     (4)可以在系统的不同部分使用相同的一些状态对象。这种共享对象的办法使与享元模式相符合的。事实上,此时这些状态对象基本上是只有行为而没有内部状态的享元模式。
     (5)状态模式的缺点是会造成大量的小的状态类;优点是使程序免于大量的条件转移语句,使代码设实际上更易于维护。
     (6)相同所选的状态子类均是从一个抽象状态类或接口继承的,Java语言的特性使得在Java中使用状态模式较为安全。多态性原则是状态模式的核心。
三、在什么情况下使用状态模式
1一个对象的行为依赖于它所处的状态,对象的行为必须随着其状态的改变而改变。
2对象的某个方法里依赖于一重或多重的条件转换语句,其中有大量的代码。状态模式把条件转移语句的每一个分支包装到一个单独的类里,这使得这些条件转移分支能够以类的方式独立存在和演化,维护这些独立的类也不再影响到系统的其它部分。
四、关于状态实现的讨论
     本模式在实现时有以下值得注意的地方
1、谁来定义状态的变化。状态模式并没有规定那一个角色决定状态发生转换的条件,如果转换条件时固定的,那么决定就应当由Context角色来做。
     然而,如果让State的子类自行决定它的下一个继任者是谁,以及在什么时候进行转换,就更有灵活性。
2、状态对象的创立和湮灭。有2种方式
     (1)动态的创立所需要的状态对象,不要创立不需要的状态对象,当不再需要某一状态对象时,便马上把次状态对象的实例湮灭掉。这对在事先不知道要使用哪一个状态对象,而一旦开始使用便不再频繁变更的情况下,是一个好注意。
     (2)事先创立所有的对象,然后不再湮灭它们。这适用于状态变化比较快和频繁、加载这些状态对象的成本较高的情况。
     对应Java系统,湮灭一个对象不是由程序完全控制的。当一个对象不再被引用时。Java的垃圾处理器就自动把它湮灭掉。但是具体在什么时候湮灭,则不是可以控制的。甚至不是可以预料的。
     (3)环境类可以把自己作为参量传给状态对象。这样,一旦需要,状态对象就可以调用环境对象。
四、状态模式与策略模式的区别
     状态模式经常与策略模式相混淆。有时候很难区分应当使用状态模式还是应当使用策略模式。
     这个时候,一个简单的方法便是考察环境角色是否有明显的状态和状态的过渡,如果环境角色只有一个状态,那么就应当使用策略模式。策略模式的特点是:一旦环境角色选择了一个具体策略类,那么整个环境类的生命周期里它都不会改变这个具体策略类。而状态模式则适用于另一种情况,即环境角色有明显的状态转移。在环境类的生命周期里,会有几个不同的状态对象被使用。
     另一个微妙的区别在于,策略模式的环境类自己选择一个具体策略类;而状态模式的环境类被外在的原因放进一个具体状态类中。
     策略模式所选的策略往往并不明显的告诉客户端它所选择的具体策略;而状态模式则相反,在状态模式里,环境角色所出的状态是明显告诉客户端的。