HardBirch

浅学设计模式之状态<state>模式

时间:12-06-01 栏目:安卓源码解析与小应用 作者:张飞不张,文采横飞 评论:8 点击: 3,097 次

State模式定义:

      不同的状态,不同的行为; 或者说,每个状态有着相应的行为.

使用情况:

        状态模式在工作流或游戏等各种系统中有大量使用,甚至是这些系统的核心功能设计,例如在典型的OA中,一个批文的状态有多种:未办;正在办理;正在批示;正在审核;已经完成等各种状态,使用状态机可以封装这个状态的变化规则,从而达到扩充状态时,不必涉及到状态的使用者。

       在网游中,一个游戏活动存在开始、开玩、正在玩、输赢等状态,使用状态模式就可以实现游戏状态的总控,而游戏状态决定了游戏的各个方面,使用状态模式可以对整个游戏架构功能实现起到决定的主导作用。


        状态模式可以有效的替换充满在程序中的if else语句:将不同条件下的行为封装在一个类里面,再给这些类一个统一的父类来约束他们。看一下状态模式的角色组成:

  1. 使用环境(Context)角色:客户程序是通过它来满足自己的需求。它定义了客户程序需要的接口;并且维护一个具体状态角色的实例,这个实例来决定当前的状态。 
  2. 状态(State)角色:定义一个接口以封装与使用环境角色的一个特定状态相关的行为。
  3. 具体状态(Concrete State)角色:实现状态角色定义的接口。

之间的协作关系:

  1.  Context将于状态相关的请求委托给当前的ConcreteState对象处理。
  2.  Context可将自身作为一个参数传递给处理该请求的状态对象,这使得状态对象在必要的时候可访问Context
  3.  Context是客户使用的主要接口,客户可用状态对象来配置一个Context,一旦一个Context配置完毕,他的客户不再需要直接与状态对象打交道。
  4. Context或者ConcreteState子类都可以决定哪个状态是另外那个状态的后继者,以及是在何种条件下进行状态转换。



状态模式实质

使用状态模式前,客户端外界需要介入改变状态,而状态改变的实现是琐碎或复杂的。

使用状态模式后,客户端外界可以直接使用事件Event实现,根本不必关心该事件导致如何状态变化,这些是由状态机等内部实现。

这是一种Event-condition-State,状态模式封装了condition-State部分。

每个状态形成一个子类,每个状态只关心它的下一个可能状态,从而无形中形成了状态转换的规则。如果新的状态加入,只涉及它的前一个状态修改和定义。

状态转换有几个方法实现:一个在每个状态实现next(),指定下一个状态;还有一种方法,设定一个StateOwner,在StateOwner设定stateEnter状态进入和stateExit状态退出行为。

状态从一个方面说明了流程,流程是随时间而改变,状态是截取流程某个时间片。


适用场合:

       (1)

        State模式在实际使用中比较多,适合"状态的切换".因为我们经常会使用If elseif else 进行状态切换, 如果针对状态的这样判断切换反复出现,我们就要联想到是否可以采取State模式了.适合于内部状态,不断循环变化的.

     (2)

一个state,包括两部分: 对象 + 对象内部的属性(属性接口+具体属性)
一个对象,要有其属性,以及其setter,getter.且设置好其初始状态+一个调用显示状态的方法(里面就是状态调用自身的显示方法).
一个属性接口,应该有一个执行的方法.
一个具体属性,须包含对象进去,实现方法中,须设置对象下一个要显示的属性-->从而在对象下次调用方法时,其属性值会变化.

代码例子:

该代码使用电梯作为模板设置了四种状态

       State接口:

public interface IState {
    void open();
    void close();
    void runing();
    void stop();
}

具体角色(Concrete State)

public class OpenState implements IState {
    private Lift lift;

    public OpenState(Lift lift){
        this.lift = lift;
    }

    @Override
    public void open() {
        // TODO Auto-generated method stub
        System.out.println("门已经开了!!!");
    }

    @Override
    public void close() {
        // TODO Auto-generated method stub
        System.out.println("好的,现在关门");
        lift.setState(lift.getCloseState());
    }

    @Override
    public void runing() {
        // TODO Auto-generated method stub
        System.out.println("现在门开着,电梯没办法运行");
    }

    @Override
    public void stop() {
        // TODO Auto-generated method stub
        System.out.println("现在门开着,电梯是停止状态");
    }

}

ublic class RunState implements IState {
    private Lift lift;

    public RunState(Lift lift){
        this.lift = lift;
    }

    @Override
    public void open() {
        // TODO Auto-generated method stub
        System.out.println("现在正在运行,没办法开门");
    }

    @Override
    public void close() {
        // TODO Auto-generated method stub
        System.out.println("现在是运行状态,门已经关闭");
    }

    @Override
    public void runing() {
        // TODO Auto-generated method stub
        System.out.println("电梯正在运行中....");
    }

    @Override
    public void stop() {
        // TODO Auto-generated method stub
        System.out.println("让电梯停止");
        lift.setState(lift.getStopState());
    }

}

public class StopState implements IState {
    private Lift lift;
    public StopState(Lift lift){
        this.lift = lift;
    }

    @Override
    public void open() {
        // TODO Auto-generated method stub
        System.out.println("现在打开电梯");
        lift.setState(lift.getOpenState());
    }

    @Override
    public void close() {
        // TODO Auto-generated method stub
        System.out.println("电梯现在关闭");
        lift.setState(lift.getStopState());
    }

    @Override
    public void runing() {
        // TODO Auto-generated method stub
        System.out.println("好吧,让电梯开始运行");
        lift.setState(lift.getRunState());
    }

    @Override
    public void stop() {
        // TODO Auto-generated method stub
        System.out.println("现在正是在停止状态");
    }

}

public class CloseState implements IState {
    private Lift lift;

    public CloseState(Lift lift){
        this.lift = lift;
    }

    @Override
    public void open() {
        // TODO Auto-generated method stub
        System.out.println("正要准备打开门");
        lift.setState(lift.getOpenState());
    }

    @Override
    public void close() {
        // TODO Auto-generated method stub
        System.out.println("现在门正在关着");
    }

    @Override
    public void runing() {
        // TODO Auto-generated method stub
        System.out.println("现在让电梯运行");
        lift.setState(lift.getRunState());
    }

    @Override
    public void stop() {
        // TODO Auto-generated method stub
        System.out.println("现在让电梯停止");
        lift.setState(lift.getStopState());
    }

}

context类:

public class Lift {
    private IState openState;
    private IState closeState;
    private IState runState;
    private IState stopState;

    private IState state ;

    public Lift(){
        openState = new OpenState(this);
        closeState = new CloseState(this);
        runState = new RunState(this);
        stopState = new StopState(this);
        state = stopState;
    }

    public void openLift(){
        state.open();
    }

    public void runLift(){
        state.runing();
    }

    public void stopLift(){
        state.stop();
    }

    public void closeLift(){
        state.close();
    }

    public void setState(IState state){
        this.state = state;
    }

    public IState getOpenState() {
        return openState;
    }
    public IState getCloseState() {
        return closeState;
    }
    public IState getRunState() {
        return runState;
    }
    public IState getStopState() {
        return stopState;
    }

}

测试类:

public class Test {
    public static void main(String[] args){
        Lift lift = new Lift();
        //好,现在打开电梯门进去
        lift.openLift();
        //关闭电梯门
        lift.closeLift();
        //让电梯开始运行
        lift.runLift();
        //电梯到了,停止
        lift.stopLift();
        //打开电梯门
        lift.openLift();

        //现在一个小朋友乱按电梯
        Lift lift2 = new Lift();
        //好,现在打开电梯门进去
        lift2.openLift();
        //又按了次开门
        lift2.openLift();
        //开门状态下,让电梯运行
        lift2.runLift();
        //好吧,不玩了,关闭电梯门
        lift2.closeLift();
        //让电梯开始运行
        lift2.runLift();
        //在运行过程中想打开门
        lift2.openLift();
        //电梯到了,停止
        lift2.stopLift();
        //打开电梯门
        lift2.openLift();
    }
}

测试结果:

现在打开电梯
好的,现在关门
现在让电梯运行
让电梯停止
现在打开电梯
---------
现在打开电梯
门已经开了!!!
现在门开着,电梯没办法运行
好的,现在关门
现在让电梯运行
现在正在运行,没办法开门
让电梯停止
现在打开电梯

状态模式与观察者模式的区别:
状态模式,也跟观察者模式一样,是一对多的模式。但观察者模式是“一”变了,所有的“多”也会更新。
状态模式,强调的是:“多”是“一”的各个状态,“一”的各个状态,进行不断的循环。
 
如何建立一与多的关系:
        “多”,都是实现一个接口的。所以,在“一”的类中,声明的是“多”的接口;若“多”中要建立与“一”的关系,只须直接在类中声明“一”即可。

状态模式与其他模式的区别:


  1. 状态模式,也跟观察者模式一样,是一对多的模式。但观察者模式是“一”变了,所有的“多”也会更新。状态模式,强调的是:“多”是“一”的各个状态,“一”的各个状态,进行不断的循环。
  2. 状态模式的主要使用方法,是作为实例变量,通过set属性方法,或者构造器把状态接口的具体实现类的实例传递进来
  3. 通常命令模式的接口中只有一个方法。而状态模式的接口中有1个或者多个方法。命令模式的主要的使用方式是参数回调模式。命令接口作为方法的参数传递进来。然后,在方法体内回调该接口。

声明: 本文由( 张飞不张,文采横飞 )原创编译,转载请保留链接: 浅学设计模式之状态<state>模式

浅学设计模式之状态<state>模式:目前有8 条留言

  1. 8楼
    MultiArrow:

    想问一下,如果新增了一种状态,除了新增一个具体角色类及修改IState以外,以前的4个具体角色类都要修改?这样的话感觉也不是很方便。。。

    2012-06-05 18:07 [回复]
  2. [reply]MultiArrow[/reply]
    为什么都要修改呢?举例说明下???

    2012-06-05 18:11 [回复]
  3. 6楼
    MultiArrow:

    [reply]aomandeshangxiao[/reply]
    假如现在我要再多增加一个维修状态repair(假设这个状态的电梯处于封闭状态,不能开关门,也不能运行),这样的话IState中增加一个方法void repairing();然后增加一个具体角色类RepairState:
    [code=java]
    public class RepairState implements IState {
    private Lift lift;
    public RepairState(Lift lift){
    this.lift = lift;
    }
    @Override
    public void open() {
    System.out.println("电梯维护中,不能打开门");
    }
    @Override
    public void close() {
    System.out.println("现在门已经关闭");
    }
    @Override
    public void runing() {
    System.out.println("电梯维护中,不能运行");
    }
    @Override
    public void stop() {
    System.out.println("电梯维护中,已经停止");
    }
    @Override
    public void repairing() {
    System.out.println("电梯维护中。。。");
    }
    }
    [/code]

    2012-06-06 11:17 [回复]
  4. [reply]MultiArrow[/reply]
    那在其他状态中不加不行吗?只在RepairState中加这个repairing方法。其实 这个只是个例子,说实话这个例子就有点为了设计模式而设计模式。使用设计模式的时候,合适就好,就是说,没必要硬往里塞。

    2012-06-06 12:00 [回复]
  5. 它只是个State模式,开始设计时就必须确定所有的状态及状态之间的转换关系。当设计过程中状态转换发生变化(状态个数变化或者一个状态到另一个状态的事件发生变化),需要修改相应类。

    2012-07-06 18:21 [回复]
  6. [reply]ao929929fei[/reply]
    恩,是的,任何设计模式都不是完美无缺的,顾此失彼吧。没有一劳永逸的模式阿。。。。

    2012-07-06 18:28 [回复]
  7. 板凳
    ao929929fei:

    [reply]aomandeshangxiao[/reply]
    虽然学习了一些设计模式,但是实际中应用的比较少,最常用的就是单一模式(Sington),搞C++的没有你们应用的多了,希望能通过学习设计模式来改变编程方式和设计方式。

    2012-07-09 12:18 [回复]
  8. [reply]ao929929fei[/reply]
    我是学java的,更少。。。学习下思想吧

    2012-07-09 13:16 [回复]

发表评论


QQ群互动

Linux系统与内核学习群:194051772

WP建站技术学习交流群:194062106

魔豆之路QR

魔豆的Linux内核之路

魔豆的Linux内核之路

优秀工程师当看优秀书籍

优秀程序员,要看优秀书!

赞助商广告

友荐云推荐