状态模式----State Pattern

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/huaishu/article/details/76439610

当一个对象内在状态改变时允许其改变行为,这个对象看起来像是改变了其类 。 Allow an object to alter its behavior when its internal state changes. The object will appear to change its class. [GoF, p305],也就是说状态模式封装的非常好,状态的变更引起了行为的变更,从外部看起来就好像这个对象对应的类发生了改变一样。

细想状态变更的实质就是一个状态与状态二维的关系表。电梯例子,通过状态的变化形成二维的表格,电梯门关闭、电梯门打开、电梯上下运载、电梯停止。

如果通过一个个遍历状态通过if  esle 完成代码不利于代码维护。



public abstract class LiftState {

    protected Context context;

    public void setContext(Context _context) {
        this.context = _context;
    }

    public abstract void open();

    public abstract void close();

    public abstract void run();

    public abstract void stop();
}
public class Context {

    // 定义出所有的电梯状态
    public final static OpenningState openningState = new OpenningState();
    public final static ClosingState closeingState = new ClosingState();
    public final static RunningState runningState = new RunningState();
    public final static StoppingState stoppingState = new StoppingState();

    // 定一个当前电梯状态
    private LiftState liftState;

    public LiftState getLiftState() {
        return liftState;
    }

    public void setLiftState(LiftState liftState) {
        this.liftState = liftState;
        // 把当前的环境通知到各个实现类中
        this.liftState.setContext(this);
    }

    public void open() {
        this.liftState.open();
    }

    public void close() {
        this.liftState.close();
    }

    public void run() {
        this.liftState.run();
    }

    public void stop() {
        this.liftState.stop();
    }
}

public class ClosingState extends LiftState { 
 
  //电梯门关闭,这是关闭状态要实现的动作 
  @Override 
  public void close() { 
  System.out.println("电梯门关闭..."); 
 
 } 
 
  //电梯门关了再打开,逗你玩呢,那这个允许呀 
  @Override 
  public void open() { 
   super.context.setLiftState(Context.openningState);  //置为门敞状态 
   super.context.getLiftState().open(); 
 } 
 
  //电梯门关了就跑,这是再正常不过了 
  @Override 
  public void run() { 
   super.context.setLiftState(Context.runningState); //设置为运行状态; 
   super.context.getLiftState().run(); 
 } 
 
  //电梯门关着,我就不按楼层 
  @Override 
  public void stop() { 
   super.context.setLiftState(Context.stoppingState);  //设置为停止状态; 
   super.context.getLiftState().stop(); 
 } 
} 


public class RunningState extends LiftState { 
  
  //电梯门关闭?这是肯定了 
  @Override 
  public void close() { 
   //do nothing 
 } 
 
  //运行的时候开电梯门?你疯了!电梯不会给你开的 
  @Override 
  public void open() { 
   //do nothing 
 } 
 
  //这是在运行状态下要实现的方法 
  @Override 
  public void run() { 
  System.out.println("电梯上下跑..."); 
 } 
 
  //这个事绝对是合理的,光运行不停止还有谁敢做这个电梯?!估计只有上帝了 
  @Override 
  public void stop() { 
   super.context.setLiftState(Context.stoppingState); //环境设置为停止状态; 
   super.context.getLiftState().stop(); 
 } 
 
}


public class StoppingState extends LiftState {

    @Override
    public void close() {
        // do nothing;
    }

    @Override
    public void open() {
        super.context.setLiftState(Context.openningState);
        super.context.getLiftState().open();
    }

    @Override
    public void run() {
        super.context.setLiftState(Context.runningState);
        super.context.getLiftState().run();
    }

    @Override
    public void stop() {
        System.out.println("电梯停止了...");
    }
}


public class Client { 
  
  public static void main(String[] args) { 
  Context context = new Context(); 
  context.setLiftState(new ClosingState()); 
   
  context.open(); 
  context.close(); 
  context.run(); 
  context.stop(); 
 } 
} 

优点:
 首先是避免了过多的 swith…case或者if..else语句的使用,避免了程序的复杂性;
 其次是很好的使用体现了开闭原则和单一职责原则,每个状态都是一个子类,增加状态就增加子类,你要修改状态,你只修改一个子类就可以了;
 最后一个好处就是封装性非常好,这也是状态模式的基本要求,状态变换放置到了类的内部来实现,外部的调用不用知道类内部如何实现状态和行为的变换。 
缺点:子类会太多,也就是类膨胀。

工作流中 Activity(节点)有初始化状态(Initialized State)、挂起状态(Suspended State)、完成状态(Completed State)等等,流程实例这么多状态,状态怎么管理呢?通过状态机(State Machine)来管理, 状态机就是 Context类的扩展版! 





猜你喜欢

转载自blog.csdn.net/huaishu/article/details/76439610
今日推荐