状态模式
来源:互联网 发布:阿里云投资了多少钱 编辑:程序博客网 时间:2024/06/10 21:23
状态模式,允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。(通过这个模式将状态封装成独立的类,并将动作委托到代表当前状态的对象)
举个栗子:
有个糖果机控制器,有四种状态:东西售完(SOLD_OUT)、还未投25分钱币(NO_QUATER)、已投25分钱币(HAS_QUATER)、卖出东西(SOLD)。
执行投入25分钱硬币:
(1)糖果机的状态是已投入25分钱:提示不能重复投入25分钱硬币。
(2)糖果机的状态是未投入25分钱:状态改为已投入。
(3)糖果机的状态是已售罄:提示不能投入25分钱硬币,因为已售罄。
(4)糖果机的状态是已卖出:提示等待,刚刚发放糖果。
同理:还有其他操作,比如退回25分钱,转动曲柄操作等等,都会经历上述的几种状态。
不推荐的代码:
将所有的状态逻辑同条件语句混杂在一起的代码:
GumballMachine.java 类:
public class GumballMachine{ final static int SOLD_OUT = 0; final static int NO_QUATER = 1; final static int HAS_QUATER = 2; final static int SOLD = 3; // 一开始被设置为“糖果售罄”, state用于追踪机器内的糖果数目 int state = SOLD_OUT; int count = 0; public GumballMachine(int count){ this.count = count; if (count > 0){ // 如果库存不为0的话,机器会进入“没有25分钱”的状态,也就是说它等着别人投入25分钱, // 如果糖果数目为0的话,机器会保持在“糖果售罄”的状态 state = NO_QUATER; } } /** * 投入25分钱,会执行这里 */ public void insertQuarter(){ if (state == HAS_QUATER){ // 已投入25分钱 System.out.println("You can't insert another quater"); } else if ( state == NO_QUATER ){ state = HAS_QUATER; System.out.println("You inserted a quater"); } else if (state == SOLD_OUT ){ System.out.println("You can't insert a quater the machine is sold out"); } else if (state == SOLD ){ // 如果顾客刚刚买了糖果,就需要稍等一下,好让状态转换完毕,恢复到“没有25分钱”状态 System.out.println("Please wait, we're already giving you a gumball"); } } /** * 退回25分钱的操作 */ public void ejectQuater() { if (state == HAS_QUATER){ System.out.println("Quater returned"); state = NO_QUATER; } else if ( state == NO_QUATER ){ System.out.println("You haven't inserted a quater"); } else if ( state == SOLD ){ // 如果顾客已经转动曲柄,就不能再退钱了,他已经拿到糖果了 System.out.println("Sorry, you already turned the crank"); } else if ( state == SOLD_OUT ){ // 如果糖果售罄,就不能接受25分钱,当然也不能退钱 System.out.println("You can't eject, you haven't inserted a quater yet"); } } /** * 转动曲柄操作 */ public void turnCrank(){ if ( state == SOLD ){ // 用户转动或曲柄,且拿到了糖果,再次转动曲柄时的提示 System.out.println("Turning twice does't get you another gumball!"); } else if ( state == NO_QUATER ){ System.out.println("You turned but there's no quater"); } else if ( state == SOLD_OUT ){ System.out.println("You turned, but there are no gumballs"); } else if ( state == HAS_QUATER ){ System.out.println("You turned..."); state = SOLD; dispense(); } } /** * 调用此方法,发放糖果 */ public void dispense(){ if ( state == SOLD ){ System.out.println("A gumball comes rolling out the slot"); count = count - 1; if ( count == 0 ){ System.out.println("Oops, out of gumballs"); state = SOLD_OUT; } else { state = NO_QUATER; } } else if ( state == NO_QUATER ) { // 以下这些是不该发生的,但如果顾客这么做了,他们得到的是错误信息,而不是得到糖果 System.out.println("You need to pay first"); } else if ( state == SOLD_OUT ){ System.out.println("No gumball dispensed"); } else if ( state == HAS_QUATER ){ System.out.println("No gumball dispensed"); } } @Override public String toString() { // 公司相关信息 String info = ""; info += "Mighty Gumball, Inc. \n"; info += "Java-enabled standing Gumball Model #2004"; String inventory = "Inventory: " + this.count + " gumballs \n"; info += inventory; if ( state == SOLD_OUT){ info += "Machine is sold out"; } else if (state == NO_QUATER){ info += "Machine is waiting for quater"; } else if (state == HAS_QUATER){ info += "Machine has a quater"; } else if (state == SOLD){ info += "Machine has sold a gumball"; } return info; }}
上述代码的测试语句如下:
public static void main(String[] args) { GumballMachine gumballMachine = new GumballMachine(5); // 总共装了5颗糖果 System.out.println(gumballMachine); // 打印出打印机的状态 gumballMachine.insertQuarter(); // 投入一枚25分钱硬币 gumballMachine.turnCrank(); // 转动曲柄,我们应该拿到糖果 System.out.println(gumballMachine); // 再一次打印出机器的状态 gumballMachine.insertQuarter(); // 投入一枚25分钱硬币 gumballMachine.ejectQuater(); // 要求机器退钱 gumballMachine.turnCrank(); // 转动曲柄,我们应该拿不到钱 System.out.println(gumballMachine); // 再次打印出打印机的状态 gumballMachine.insertQuarter(); // 投入一枚25分钱的硬币 gumballMachine.turnCrank(); // 转动曲柄,我们应该拿到糖果 gumballMachine.insertQuarter(); // 投入一枚25分钱硬币 gumballMachine.turnCrank(); // 转动曲柄,我们应该拿到糖果 gumballMachine.ejectQuater(); // 要求机器退钱 System.out.println(gumballMachine); gumballMachine.insertQuarter(); gumballMachine.insertQuarter(); // 放进两枚25分钱硬币 gumballMachine.turnCrank(); // 转动曲柄,我们应该拿到糖果 gumballMachine.insertQuarter(); // 做压力测试 gumballMachine.turnCrank(); gumballMachine.insertQuarter(); gumballMachine.turnCrank(); System.out.println(gumballMachine); // 再一次打印出机器的状态}输出结果为:
Mighty Gumball, Inc.
Java-enabled standing Gumball Model #2004Inventory: 5 gumballs
Machine is waiting for quater
You inserted a quater
You turned...
A gumball comes rolling out the slot
Mighty Gumball, Inc.
Java-enabled standing Gumball Model #2004Inventory: 4 gumballs
Machine is waiting for quater
You inserted a quater
Quater returned
You turned but there's no quater
Mighty Gumball, Inc.
Java-enabled standing Gumball Model #2004Inventory: 4 gumballs
Machine is waiting for quater
You inserted a quater
You turned...
A gumball comes rolling out the slot
You inserted a quater
You turned...
A gumball comes rolling out the slot
You haven't inserted a quater
Mighty Gumball, Inc.
Java-enabled standing Gumball Model #2004Inventory: 2 gumballs
Machine is waiting for quater
You inserted a quater
You can't insert another quater
You turned...
A gumball comes rolling out the slot
You inserted a quater
You turned...
A gumball comes rolling out the slot
Oops, out of gumballs
You can't insert a quater the machine is sold out
You turned, but there are no gumballs
Mighty Gumball, Inc.
Java-enabled standing Gumball Model #2004Inventory: 0 gumballs
Machine is sold out
分析:
上面的代码通过巨大的、整块的条件语句,让代码变的难以维护。
解决办法:
通过将不同状态封装在不同的对象中,可以让状态变得很干净,在以后理解和维护它们时,就可以省下很多功夫。
状态模式实现的代码如下:
创建一个State接口,所有的状态都必须实现这个接口
State.java 类如下:
public interface State { void insertQuater(); void ejectQuater(); void turnCrank(); void dispense();}
糖果机的几种类对应的状态如下:
SoldState.java 类:
public class SoldState implements State{ GumballMachine gumballMachine; public SoldState(GumballMachine gumballMachine){ this.gumballMachine = gumballMachine; } @Override public void insertQuater() { System.out.println("Please wait, we're already giving you a gumball"); } @Override public void ejectQuater() { System.out.println("Sorry, you already turned the crank"); } @Override public void turnCrank() { System.out.println("Turning twice doesn't get you another gumball"); } @Override public void dispense() { gumballMachine.releaseBall(); if (gumballMachine.getCount() > 0){ gumballMachine.setState(gumballMachine.getNoQuaterState()); } else { System.out.println("Oops, out of gumballs"); gumballMachine.setState(gumballMachine.getSoldOutState()); } }}
SoldOutState.java 类:
public class SoldOutState implements State { GumballMachine gumballMachine; public SoldOutState(GumballMachine gumballMachine){ this.gumballMachine = gumballMachine; } @Override public void insertQuater() { System.out.println("You can't insert a quater, the machine is sold out"); } @Override public void ejectQuater() { System.out.println("You can't eject, you haven't inserted a quater yet"); } @Override public void turnCrank() { System.out.println("You turned, but there are no gumballs"); } @Override public void dispense() { System.out.println("No gumball dispensed"); }}
NoQuaterState.java 类:
public class NoQuaterState implements State { GumballMachine gumballMachine; public NoQuaterState(GumballMachine gumballMachine){ this.gumballMachine = gumballMachine; } @Override public void insertQuater() { System.out.println("You inserted a quater"); gumballMachine.setState(gumballMachine.getHasQuaterState()); } @Override public void ejectQuater() { System.out.println("You haven't inserted a quater"); } @Override public void turnCrank() { System.out.println("You turned, but there's no quater"); } @Override public void dispense() { System.out.println("You need to pay first"); }}
HasQuaterState.java 类:
public class HasQuaterState implements State { Random randomWinner = new Random(System.currentTimeMillis()); GumballMachine gumballMachine; public HasQuaterState(GumballMachine gumballMachine){ this.gumballMachine = gumballMachine; } @Override public void insertQuater() { // 已经放入15分钱,不允许再放入15分钱 System.out.println("You can't insert another quater"); } @Override public void ejectQuater() { // 退钱操作,然后将机器的状态置为无15分钱的状态 System.out.println("Quater returned"); gumballMachine.setState(gumballMachine.getNoQuaterState()); } @Override public void turnCrank() { // 曲柄转动时,转动出相应的东西,并将机器状态置为已经售出 System.out.println("You turned..."); int winner = randomWinner.nextInt(10); if((winner == 0) && (gumballMachine.getCount() > 1)){ // 这里因为winner的值是0到9中的任意一个我们取0,则是10%的概率问题 gumballMachine.setState(gumballMachine.getWinnerState()); }else{ gumballMachine.setState(gumballMachine.getSoldState()); } } @Override public void dispense() { // 此状态的另一个不恰当的动作 System.out.println("No gumball dispensed"); }}
WinnerState.java 类如下:
public class WinnerState implements State{ GumballMachine gumballMachine; public WinnerState(GumballMachine gumballMachine){ this.gumballMachine = gumballMachine; } @Override public void insertQuater() { System.out.println("Please wait, we're already giving you a gumball"); } @Override public void ejectQuater() { System.out.println("Sorry, you already turned the crank"); } @Override public void turnCrank() { System.out.println("Turning twice doesn't get you another gumball"); } @Override public void dispense() { System.out.println("YOU'RE A WINNER! you get two gumballs for you quater"); gumballMachine.releaseBall(); if(gumballMachine.getCount() == 0){ gumballMachine.setState(gumballMachine.getSoldOutState()); // 如果还有第二颗糖果的话,我们就把它释放出来 } else { gumballMachine.releaseBall(); if (gumballMachine.getCount() > 0){ gumballMachine.setState(gumballMachine.getNoQuaterState()); } else { System.out.println("Oops, out of gumballs"); gumballMachine.setState(gumballMachine.getSoldOutState()); } } }}
GumballMachine.java 类:
public class GumballMachine { State soldOutState; State noQuaterState; State hasQuaterState; State soldState; State winnerState; State state = soldOutState; int count = 0; public GumballMachine(int numberGumballs){ soldOutState = new SoldOutState(this); noQuaterState = new NoQuaterState(this); hasQuaterState = new HasQuaterState(this); soldState = new SoldState(this); winnerState = new WinnerState(this); if (numberGumballs > 0){ state = noQuaterState; this.count = numberGumballs; } } public void insertQuater(){ state.insertQuater(); } public void ejectQuater(){ state.ejectQuater(); } public void turnCrank(){ state.turnCrank(); state.dispense(); } public State getState() { return state; } public void setState(State state) { this.state = state; } void releaseBall(){ System.out.println("A gumball come rolling out the slot..."); if ( count != 0 ){ count = count - 1; } } public State getSoldOutState() { return soldOutState; } public void setSoldOutState(State soldOutState) { this.soldOutState = soldOutState; } public State getNoQuaterState() { return noQuaterState; } public void setNoQuaterState(State noQuaterState) { this.noQuaterState = noQuaterState; } public State getHasQuaterState() { return hasQuaterState; } public void setHasQuaterState(State hasQuaterState) { this.hasQuaterState = hasQuaterState; } public State getSoldState() { return soldState; } public void setSoldState(State soldState) { this.soldState = soldState; } public int getCount() { return count; } public void setCount(int count) { this.count = count; } public State getWinnerState() { return winnerState; } public void setWinnerState(State winnerState) { this.winnerState = winnerState; } @Override public String toString() { // 公司相关信息 String info = ""; info += "Mighty Gumball, Inc. \n"; info += "Java-enabled standing Gumball Model #2004"; String inventory = "Inventory: " + this.count + " gumballs \n"; info += inventory; if ( state instanceof SoldOutState){ info += "Machine is sold out"; } else if (state instanceof NoQuaterState){ info += "Machine is waiting for quater"; } else if (state instanceof HasQuaterState){ info += "Machine has a quater"; } else if (state instanceof SoldState){ info += "Machine has sold a gumball"; } return info; }}
编写一个测试类如下:
GumballMachineTestDrive.java 类:
public static void main(String[] args) { GumballMachine gumballMachine = new GumballMachine(5); System.out.println(gumballMachine); gumballMachine.insertQuater(); gumballMachine.turnCrank(); System.out.println(gumballMachine); gumballMachine.insertQuater(); gumballMachine.turnCrank(); gumballMachine.insertQuater(); gumballMachine.turnCrank(); System.out.println(gumballMachine);}
输出:
Mighty Gumball, Inc.
Java-enabled standing Gumball Model #2004Inventory: 5 gumballs
Machine is waiting for quater
You inserted a quater
You turned...
A gumball comes rolling out the slot
Mighty Gumball, Inc.
Java-enabled standing Gumball Model #2004Inventory: 4 gumballs
Machine is waiting for quater
You inserted a quater
Quater returned
You turned but there's no quater
Mighty Gumball, Inc.
Java-enabled standing Gumball Model #2004Inventory: 4 gumballs
Machine is waiting for quater
You inserted a quater
You turned...
A gumball comes rolling out the slot
You inserted a quater
You turned...
A gumball comes rolling out the slot
You haven't inserted a quater
Mighty Gumball, Inc.
Java-enabled standing Gumball Model #2004Inventory: 2 gumballs
Machine is waiting for quater
You inserted a quater
You can't insert another quater
You turned...
A gumball comes rolling out the slot
You inserted a quater
You turned...
A gumball comes rolling out the slot
Oops, out of gumballs
You can't insert a quater the machine is sold out
You turned, but there are no gumballs
Mighty Gumball, Inc.
Java-enabled standing Gumball Model #2004Inventory: 0 gumballs
Machine is sold out
分析:
上述代码通过将5种不同的状态:
SoldState.java 正在销售的状态;
SoldOutState.java 售罄的状态;
NoQuaterState.java 未投入25分钱的状态;
HasQuaterState.java 投入25分钱状态;以及后期新加入的状态WinnerState.java可以售出两个糖果的状态;
所有的这些状态,都是寄生在一台糖果机GumballMachine.java 类上。
GumballMachine.java 和所有状态类是组合的关系,GumballMachine.java中通过字段包含了所有的状态,而各个状态类中字段有糖果机类的实例。
初始时,通过GumballMachine gumballMachine = new GumballMachine(5);将糖果机的糖果数量设置为5,而且如果糖果的数量大于0,则初始的状态是NoQuaterState,此时如果执行gumballMahcine的insert,即执行了NoQuaterState中的insert,则相应的状态会改变成HasQuaterState,此时,执行turnCrank则状态会变成soldState状态,然后调用相关的dispense方法。(注意:这里的state,全程只有一种状态,在不断的切换)
- 状态模式(状态变化)
- 状态模式
- 状态模式
- 状态模式
- 状态模式
- 状态模式
- 状态模式
- 状态模式
- 状态模式
- 状态模式
- 状态模式
- 状态模式
- 状态模式
- 状态模式
- 状态模式
- 状态模式
- 状态模式
- 状态模式
- 听说可以赚积分?
- java基础4
- PAT (Basic Level) Practise (中文)1005. 继续(3n+1)猜想 (25)
- 《看不见的森林:林中自然笔记》书摘二
- Design Pattern 2: Proxy
- 状态模式
- POJ-2063 Investment (完全背包 简单题)
- 计算机网络 学习摘要(4)
- nlp领域的研究入门
- [leetcode] 39. Combination Sum
- [LeetCode] 13. Roman to Integer ❤
- 并查集求联通块
- 《看不见的森林:林中自然笔记》书摘三
- 【练习】二叉树的遍历