设计模式学习--状态模式(State Pattern)
概述
———————————————————————————————————————————————————
状态模式—允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。
OO原则
———————————————————————————————————————————————————
- 封装变化
- 多用组合,少用继承
- 针对接口编程,不针对实现编程
- 为交互对象之间的松耦合设计而努力
- 类应该对扩展开放,对修改关闭
- 依赖抽象,不要以来具体类
- 只和朋友交谈
- 别找我,我会找你
- 类应该只有一个改变的理由
要点
———————————————————————————————————————————————————
- 状态模式允许一个对象基于内部状态而拥有不用的行为。
- 和程序状态机(PSM)不同,状态模式用类代表状态。
- Context会将行为委托给当前状态对象。
- 通过将每个状态封装进一个类,我们把以后需要做的任何改变局部化了。
- 状态模式和策略模式有相同的类图,但是它们的意图不同。
- 策略模式通常会用行为或算法来配置Context类。
- 状态模式允许Context随着状态的改变而改变行为。
- 状态转换可以由State类或Context类控制。
- 使用状态模式通常会导致设计中类的数目大量增加。
- 状态类可以被多个Context实例共享。
例子 糖果机
———————————————————————————————————————————————————
先来看一下状态模式的类图
1. Context
定义客户感兴趣的接口。
维护一个ConcreteState子类的实例,这个实例定义当前状态。
GumballMachine.java
package gumballstate;
/**
* 2013/7/12
* @author wwj
* 糖果机
* 利用状态模式
*/
public class GumballMachine {
State soldOutState; //售空状态
State noQuarterState; //没有投入25分钱
State hasQuarterState; //有25分钱了
State soldState; //出售状态
State winnerState; //10%的中奖率
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;
}
public State getState() {
return state;
}
void releaseBall() {
System.out.println("A gumball comes rolling out the slot...");
if(count != 0) {
count = count - 1;
}
}
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 int getCount() {
return count;
}
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();
}
}
2.State
定义一个接口以封装与Context的一个特定状态相关的行为。
State.java
[java] view plain
copy
print ?
- package gumballstate;
-
-
-
-
-
-
- public interface State {
- void insertQuarter();
- void ejectQuarter();
- void turnCrank();
- void dispense();
- }
package gumballstate;
/**
* 状态接口
* @author wwj
*
*/
public interface State {
void insertQuarter();
void ejectQuarter();
void turnCrank();
void dispense();
}
3.ConcreteStateSubClasses
每一个子类实现与context的一个状态相关的行为
NoQuarterState.java
[java] view plain
copy
print ?
- package gumballstate;
-
-
-
-
-
-
-
- public class NoQuarterState implements State {
- GumballMachine gumballMachine;
-
- public NoQuarterState(GumballMachine gumballMachine2) {
- this.gumballMachine = gumballMachine2;
- }
-
- @Override
- public void insertQuarter() {
- System.out.println("You inserted a quarter");
- }
-
- @Override
- public void ejectQuarter() {
- System.out.println("You haven't inserted a quarter");
- }
-
- @Override
- public void turnCrank() {
- System.out.println("You turned, but there's no quarter");
- }
-
- @Override
- public void dispense() {
- System.out.println("You need to pay first");
- }
-
- }
package gumballstate;
/**
* 2013/7/12
* @author wwj
* 实现状态接口状态类:没有25分钱
*/
public class NoQuarterState implements State {
GumballMachine gumballMachine;
public NoQuarterState(GumballMachine gumballMachine2) {
this.gumballMachine = gumballMachine2;
}
@Override
public void insertQuarter() { //如果有人投入了25分钱,就将状态转换为HasQuarterState
System.out.println("You inserted a quarter");
}
@Override
public void ejectQuarter() { //如果没给钱,就不能要求退钱
System.out.println("You haven't inserted a quarter");
}
@Override
public void turnCrank() { //如果没给钱,就不能要求糖果
System.out.println("You turned, but there's no quarter");
}
@Override
public void dispense() { //如果没得到钱,我们就不能发放糖果
System.out.println("You need to pay first");
}
}
HasQuarterState.java
[java] view plain
copy
print ?
- package gumballstate;
-
- 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";
- }
- }
package gumballstate;
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); //参数0~10的随机数
if((winner == 0) && (gumballMachine.getCount() > 1)) { //如果随机树为0,且足够的糖果的话,则可以得到两颗糖果
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";
}
}
SoldState.java
[java] view plain
copy
print ?
- package gumballstate;
-
- public class SoldState implements State {
-
- GumballMachine gumballMachine;
-
- public SoldState(GumballMachine gumballMachine) {
- this.gumballMachine = gumballMachine;
- }
-
- public void insertQuarter() {
- System.out.println("Please wait, we're already giving you a gumball");
- }
-
- public void ejectQuarter() {
- System.out.println("Sorry, you already turned the crank");
- }
-
- public void turnCrank() {
- System.out.println("Turning twice doesn't get you another gumball!");
- }
-
- public void dispense() {
- gumballMachine.releaseBall();
- if (gumballMachine.getCount() > 0) {
- gumballMachine.setState(gumballMachine.getNoQuarterState());
- } else {
- System.out.println("Oops, out of gumballs!");
- gumballMachine.setState(gumballMachine.getSoldOutState());
- }
- }
-
- public String toString() {
- return "dispensing a gumball";
- }
- }
package gumballstate;
public class SoldState implements State {
GumballMachine gumballMachine;
public SoldState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
public void insertQuarter() {
System.out.println("Please wait, we're already giving you a gumball");
}
public void ejectQuarter() {
System.out.println("Sorry, you already turned the crank");
}
public void turnCrank() {
System.out.println("Turning twice doesn't get you another gumball!");
}
public void dispense() {
gumballMachine.releaseBall();
if (gumballMachine.getCount() > 0) {
gumballMachine.setState(gumballMachine.getNoQuarterState());
} else {
System.out.println("Oops, out of gumballs!");
gumballMachine.setState(gumballMachine.getSoldOutState());
}
}
public String toString() {
return "dispensing a gumball";
}
}
SoldOutState.java
[java] view plain
copy
print ?
- package gumballstate;
-
- public class SoldOutState implements State {
- GumballMachine gumballMachine;
-
- public SoldOutState(GumballMachine gumballMachine) {
- this.gumballMachine = gumballMachine;
- }
-
- public void insertQuarter() {
- System.out.println("You can't insert a quarter, the machine is sold out");
- }
-
- public void ejectQuarter() {
- System.out.println("You can't eject, you haven't inserted a quarter yet");
- }
-
- public void turnCrank() {
- System.out.println("You turned, but there are no gumballs");
- }
-
- public void dispense() {
- System.out.println("No gumball dispensed");
- }
-
- public String toString() {
- return "sold out";
- }
- }
package gumballstate;
public class SoldOutState implements State {
GumballMachine gumballMachine;
public SoldOutState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
public void insertQuarter() {
System.out.println("You can't insert a quarter, the machine is sold out");
}
public void ejectQuarter() {
System.out.println("You can't eject, you haven't inserted a quarter yet");
}
public void turnCrank() {
System.out.println("You turned, but there are no gumballs");
}
public void dispense() {
System.out.println("No gumball dispensed");
}
public String toString() {
return "sold out";
}
}
WinnerState.java
[java] view plain
copy
print ?
- package gumballstate;
-
- public class WinnerState implements State {
- GumballMachine gumballMachine;
-
- public WinnerState(GumballMachine gumballMachine) {
- this.gumballMachine = gumballMachine;
- }
-
- public void insertQuarter() {
- System.out.println("Please wait, we're already giving you a Gumball");
- }
-
- public void ejectQuarter() {
- System.out.println("Please wait, we're already giving you a Gumball");
- }
-
- public void turnCrank() {
- System.out.println("Turning again doesn't get you another gumball!");
- }
-
- public void dispense() {
- System.out.println("YOU'RE A WINNER! You get two gumballs for your quarter");
- gumballMachine.releaseBall();
- if (gumballMachine.getCount() == 0) {
- gumballMachine.setState(gumballMachine.getSoldOutState());
- } else {
- gumballMachine.releaseBall();
- if (gumballMachine.getCount() > 0) {
- gumballMachine.setState(gumballMachine.getNoQuarterState());
- } else {
- System.out.println("Oops, out of gumballs!");
- gumballMachine.setState(gumballMachine.getSoldOutState());
- }
- }
- }
-
- public String toString() {
- return "despensing two gumballs for your quarter, because YOU'RE A WINNER!";
- }
- }
package gumballstate;
public class WinnerState implements State {
GumballMachine gumballMachine;
public WinnerState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
public void insertQuarter() {
System.out.println("Please wait, we're already giving you a Gumball");
}
public void ejectQuarter() {
System.out.println("Please wait, we're already giving you a Gumball");
}
public void turnCrank() {
System.out.println("Turning again doesn't get you another gumball!");
}
public void dispense() {
System.out.println("YOU'RE A WINNER! You get two gumballs for your quarter");
gumballMachine.releaseBall();
if (gumballMachine.getCount() == 0) {
gumballMachine.setState(gumballMachine.getSoldOutState());
} else {
gumballMachine.releaseBall();
if (gumballMachine.getCount() > 0) {
gumballMachine.setState(gumballMachine.getNoQuarterState());
} else {
System.out.println("Oops, out of gumballs!");
gumballMachine.setState(gumballMachine.getSoldOutState());
}
}
}
public String toString() {
return "despensing two gumballs for your quarter, because YOU'RE A WINNER!";
}
}
测试
[java] view plain
copy
print ?
- package gumballstate;
-
- public class GumballMachineTestDrive {
-
- public static void main(String[] args) {
- GumballMachine gumballMachine =
- new GumballMachine(10);
-
- System.out.println(gumballMachine);
-
- gumballMachine.insertQuarter();
- gumballMachine.turnCrank();
- gumballMachine.insertQuarter();
- gumballMachine.turnCrank();
-
- System.out.println(gumballMachine);
-
- gumballMachine.insertQuarter();
- gumballMachine.turnCrank();
- gumballMachine.insertQuarter();
- gumballMachine.turnCrank();
-
- System.out.println(gumballMachine);
-
- gumballMachine.insertQuarter();
- gumballMachine.turnCrank();
- gumballMachine.insertQuarter();
- gumballMachine.turnCrank();
-
- System.out.println(gumballMachine);
-
- gumballMachine.insertQuarter();
- gumballMachine.turnCrank();
- gumballMachine.insertQuarter();
- gumballMachine.turnCrank();
-
- System.out.println(gumballMachine);
-
- gumballMachine.insertQuarter();
- gumballMachine.turnCrank();
- gumballMachine.insertQuarter();
- gumballMachine.turnCrank();
-
- System.out.println(gumballMachine);
- }
- }
package gumballstate;
public class GumballMachineTestDrive {
public static void main(String[] args) {
GumballMachine gumballMachine =
new GumballMachine(10);
System.out.println(gumballMachine);
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
System.out.println(gumballMachine);
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
System.out.println(gumballMachine);
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
System.out.println(gumballMachine);
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
System.out.println(gumballMachine);
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
System.out.println(gumballMachine);
}
}
Mighty Gumball, Inc.
Java-enabled Standing Gumball Model #2004
Inventory: 10 gumballs
Machine is waiting for quarter
You inserted a quarter
You turned...
A gumball comes rolling out the slot...
You inserted a quarter
You turned...
A gumball comes rolling out the slot...
Mighty Gumball, Inc.
Java-enabled Standing Gumball Model #2004
Inventory: 8 gumballs
Machine is waiting for quarter
You inserted a quarter
You turned...
A gumball comes rolling out the slot...
You inserted a quarter
You turned...
A gumball comes rolling out the slot...
Mighty Gumball, Inc.
Java-enabled Standing Gumball Model #2004
Inventory: 6 gumballs
Machine is waiting for quarter
You inserted a quarter
You turned...
A gumball comes rolling out the slot...
You inserted a quarter
You turned...
A gumball comes rolling out the slot...
Mighty Gumball, Inc.
Java-enabled Standing Gumball Model #2004
Inventory: 4 gumballs
Machine is waiting for quarter
You inserted a quarter
You turned...
A gumball comes rolling out the slot...
You inserted a quarter
You turned...
A gumball comes rolling out the slot...
Mighty Gumball, Inc.
Java-enabled Standing Gumball Model #2004
Inventory: 2 gumballs
Machine is waiting for quarter
You inserted a quarter
You turned...
A gumball comes rolling out the slot...
You inserted a quarter
You turned...
A gumball comes rolling out the slot...
Oops, out of gumballs!
Mighty Gumball, Inc.
Java-enabled Standing Gumball Model #2004
Inventory: 0 gumballs
Machine is sold out