首页 > 代码库 > Head First 设计模式 --10 状态模式

Head First 设计模式 --10 状态模式

状态模式:允许对象在内部状态改变时改变他的行为,对象看起来好像修改了他的类。

用到的设计原则
1、封装变化
2、多用组合,少用继承
3、针对接口编程,不针对实现编程
4、松耦合
5、对扩展开放,对修改关闭
6、依赖抽象,而不依赖具体
7、只和朋友交谈
8、别找我,我会找你
9、类应该只有一个修改的理由 

例子来自《Head First设计模式》,糖果机的例子

interface State {

  public void insertQuarter();

  public void ejectQuarter();

  public void turnCrank();

  public void dispense();
}

class NoQuarterState implements State {
  GumballMachine gumballMachine;

  public NoQuarterState(GumballMachine gumballMachine) {
    this.gumballMachine = gumballMachine;
  }

  public void insertQuarter() {
    System.out.println("You inserted a quarter");
    gumballMachine.setState(gumballMachine.hasQuarterState);
  }

  public void ejectQuarter() {
    System.out.println("You haven‘t inserted a quarter");
  }

  public void turnCrank() {
    System.out.println("You turned, but there‘s no quarter");
  }

  public void dispense() {
    System.out.println("You need to pay first");
  }

  public String toString() {
    return "waiting for quarter";
  }
}

class HasQuarterState implements State {
  Random randomWinner = new Random(System.currentTimeMillis());
  GumballMachine gumballMachine;

  public HasQuarterState(GumballMachine gumballMachine) {
    this.gumballMachine = gumballMachine;
  }

  public void insertQuarter() {
    System.out.println("You can‘t insert another quarter");
  }

  public void ejectQuarter() {
    System.out.println("Quarter returned");
    gumballMachine.setState(gumballMachine.noQuarterState);
  }

  public void turnCrank() {
    System.out.println("You turned...");

    int winner = randomWinner.nextInt(10);
    if ((winner == 0) && (gumballMachine.count > 1)) {
      gumballMachine.setState(gumballMachine.winnerState);
    } else {
      gumballMachine.setState(gumballMachine.soldOutState);
    }
  }

  public void dispense() {
    System.out.println("No gumball dispensed");
  }

  public String toString() {
    return "waiting for turn of crank";
  }
}

class GumballMachine {
  State soldOutState;
  State noQuarterState;
  State hasQuarterState;
  State soldState;
  State winnerState;

  State state = soldOutState;
  int count = 0;

  public GumballMachine(int numberGumballs) {// soldOutState = new SoldOutState(this);
    noQuarterState = new NoQuarterState(this);
    hasQuarterState = new HasQuarterState(this);
    // soldState = new SoldState(this);
    // winnerState = new WinnerState(this);

    this.count = numberGumballs;
    if (numberGumballs > 0) {
      state = noQuarterState;
    }
  }

  public void insertQuarter() {
    state.insertQuarter();
  }

  public void ejectQuarter() {
    state.ejectQuarter();
  }

  public void turnCrank() {
    state.turnCrank();
    state.dispense();
  }

  void setState(State state) {
    this.state = state;
  }

  void releaseBall() {
    System.out.println("A gumball comes rolling out the slot...");
    if (count != 0) {
      count = count - 1;
    }
  }

}

public class StateTest {
  public static void main(String[] args) {
    GumballMachine gumballMachine = new GumballMachine(10);

    gumballMachine.insertQuarter();
    gumballMachine.turnCrank();
    gumballMachine.insertQuarter();
    gumballMachine.turnCrank();
  }
}

类图:

技术分享

 

 上面的代码运行不了。缺少三种State,这里只是看一下要表达的意思。

装填模式将状态封装成独立的类,并将每个动作委托给当前状态的对象。如果对象能够完全改变它的行为,那么你会觉得,这个对象实际是从别的类实例化出来的,而实际上,我们是用组合通过简单引用不同的状态对象来造成类的改变的假象。

当我们看到上面的类图时,会发现这个类图和策略模式的类图是一样的。
策略模式:我们将一群行为封装在状态对象中,context的行为随时可委托到哪个状态对象中。随着状态的改变,以反应context的内部的状态。但是context的客户对于状态对象了解不多。状态模式代替多条件判断的设计方案,通过包装状态对象,在context内简单地改变状态对象。
装填模式:通常是主动指定context所要组合的对象是哪一个。这个对象一般情况不会改变,因为对于程序而言,他就是这个类型的,具有特定的行为。一般来说,策略模式是除了继承外一种弹性的设计方案。

状态模式:封装基于装填的行为,并将行为委托到当前状态
策略模式:将可以减缓的行为封装起来,然后使用委托的方法决定使用那一个行为
模板方法模式:由子类决定如何实现算法中的某个步骤

Head First 设计模式 --10 状态模式