您的位置:首页 > 编程语言 > Java开发

设计模式之状态模式

2016-09-16 16:43 232 查看

1.状态模式

  基本常识:策略模式和状态模式是双胞胎,在出生时才分开。

  状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。这个模式将状态封装成为独立的类,并将动作委托到代表当前状态的对象,使得行为会随着内部状态而改变。从客户的视角来看:如果说你使用的对象能够完全改变它的行为,那么你会觉得,这个对象实际上是从别的类实例化而来的。然而,实际上是由依照模式来使用组合通过简单引用不同状态的对象来造成类改变的假象。

2.状态模式与策略模式的比较

  策略模式是围绕可以互换的算法来创建成功业务的。然而,状态走的是更崇高的路,它通过改变对象内部的状态来帮助对象控制自己的行为。

  一般来说,我们把策略模式想成是除了继承之外的一种弹性替代方案。有了策略模式可以通过组合不同的对象来改变行为。

  对于状态模式来说,可以看作是不用在context中放置许多条件判断的替代方案。通过将行为包装进状态对象中,你可以通过在context内简单地改变状态对象来改变context的行为。

3.状态模式的结构



State类,抽象状态类,定义一个接口以封装与Context的一个特定状态相关的行为

public interface State {
public abstract void handle();
}


ConcreteState类,具体状态,每一个子类实现一个与Context的一个状态相关的行为。

public class ConcreateStateA implements State{
Context context;
@override
public void handle(Context context){
this.context = context;
}
}


Context类,维护一个ConcreteState实例,这个实例定义着当前的状态;或组合每种State子类实例,节省频繁创建实例的开销。(此处例子为组合每种实例)

public class Context{
State concreteStateA;
State concreteStateB;

State state = concreteStateA; //当前状态,默认为状态A

public Context(){
concreteStateA = new ConcreteStateA(this);
concreteStateB = new ConcreteStateB(this);
//...
}

public void request(){
state.handle();  //委托至当前状态执行方法
}

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

public State getState() {
return state;
}

public State getConcreteStateA() {
return concreteStateA;
}

public State getConcreteStateB() {
return concreteStateB;
}
}


4.状态模式的示例

糖果制造机的在经过不同条件下的状态转换,以状态模式来实现此程序(例子来源于Head Frist)

  I. 首先,我们定义一个State接口。在这个接口内,系统的每个动作都有一个对应的方法。

  II. 然后为系统中的每个状态实现状态类。这些类将负责在对应的状态下进行机器的行为。

  III. 最后,我们要摆脱旧的条件代码,取而代之的方式是,将动作委托到状态类。

状态图:



Java实现代码:

(1)State接口,定义状态功能

package State;

public interface State {

public void insertQuarter();
public void ejectQuarter();
public void turnCrank();
public void dispense();
}


(2)具体状态类,实现不同状态下的功能:

I. HasQuarterState(有25分钱)

package State;

import java.util.Random;

public 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.getNoQuarterState());
}

public void turnCrank() {
System.out.println("You turned...");
int winner = randomWinner.nextInt(10);
if ((winner == 0) && (gumballMachine.getCount() > 1)) {
gumballMachine.setState(gumballMachine.getWinnerState());
} else {
gumballMachine.setState(gumballMachine.getSoldState());
}
}

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

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


II. NoQuarterState(没有25分钱)

package State;

public 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.getHasQuarterState());
}

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";
}
}


(3)Context类,糖果制造机

package State;

public 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;
}
}

int getCount() {
return count;
}

void refill(int count) {
this.count = count;
state = noQuarterState;
}

public State getState() {
return state;
}

public State getSoldOutState() {
return soldOutState;
}

public State getNoQuarterState() {
return noQuarterState;
}

public State getHasQuarterState() {
return hasQuarterState;
}

public State getSoldState() {
return soldState;
}

public State getWinnerState() {
return winnerState;
}

public String toString() {
StringBuffer result = new StringBuffer();
result.append("\nMighty Gumball, Inc.");
result.append("\nJava-enabled Standing Gumball Model #2004");
result.append("\nInventory: " + count + " gumball");
if (count != 1) {
result.append("s");
}
result.append("\n");
result.append("Machine is " + state + "\n");
return result.toString();
}
}


5.总结

  1)状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。

  2)状态模式通过把各种状态逻辑分布到State的子类之间,来减少相互间的依赖。

  3)当一个对象的行为取决于它的状态时,并且它必须在运行时刻根据状态改变它的行为时,就可以考虑使用状态模式。

  4)面向对象设计希望做到代码的责任分解,过长的方法及具有很多判断分支会使类违背“单一职责原则”。

  5)状态类可以被多个Context实例共享。

参考资料:

1.《Head Frist设计模式》

2.《大话设计模式》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息