一、状态模式
允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。
简单来说,就是用一个“Sate”状态类接口,里面规定了自身不同操作,然后根据自身需要每一个状态都生成一个类。
二、项目背景
糖果机有四种状态,投钱状态,没有投钱状态,转动曲柄状态,售馨状态。
请看原生代码:
package com.oyhp.atom;
//糖果机
public class GumballMachine {
final static int SOLD_OUT = 0; //糖果售馨
final static int NO_QUARTER = 1; //没有25分钱
final static int HAS_QUARTER = 2; //有25分钱
final static int SOLD = 3; //售出糖果
int state = SOLD_OUT;
int count = 0;
public GumballMachine(int count) {
// TODO Auto-generated constructor stub
this.count = count;
if(count > 0){
state = NO_QUARTER;
}
}
//现在投入25分钱
public void insertQuarter(){
if(state == HAS_QUARTER){
System.out.println("你已经投过25分钱了,无法再继续投入");
}else if(state == NO_QUARTER){
state = HAS_QUARTER;
System.out.println("你已经投入25分钱");
}else if(state == SOLD_OUT){
System.out.println("无法投入25分钱,因为糖果已经售完");
}else if(state == SOLD){
System.out.println("请等待,正在售出糖果");
}
}
//退回25分钱
public void ejectQuarter(){
if(state == HAS_QUARTER){
System.out.println("25分钱已退回");
state = NO_QUARTER;
}else if(state == NO_QUARTER){
System.out.println("你并没有投入钱");
}else if(state == SOLD){
System.out.println("抱歉,糖果正在售出");
}else if(state == SOLD_OUT){
System.out.println("你并没有投入25分钱,也无法退回");
}
}
//顾客试着转动售出曲柄
public void turnCrank(){
if(state == HAS_QUARTER){
System.out.println("正在转动曲柄......");
state = SOLD;
dispense();
}else if(state == NO_QUARTER){
System.out.println("正在转动曲柄,但因为你没有投钱,所以无法售出糖果");
}else if(state == SOLD){
System.out.println("抱歉,无法转动两次曲柄");
}else if(state == SOLD_OUT){
System.out.println("正在转动曲柄,但没有糖果了,无法售出糖果");
}
}
//发放糖果
public void dispense(){
if(state == HAS_QUARTER){
System.out.println("没有糖果售出");
}else if(state == NO_QUARTER){
System.out.println("你需要先支付......");
}else if(state == SOLD){
System.out.println("正在售出糖果");
if(count <= 0){
System.out.println("抱歉无法售出糖果,因为糖果已售馨");
state = SOLD_OUT;
}else{
System.out.println("糖果已售出");
count = count - 1;
state = NO_QUARTER;
}
}else if(state == SOLD_OUT){
System.out.println("没有糖果售出");
}
}
@Override
public String toString() {
return "GumballMachine [state=" + state + ", count=" + count + "]";
}
}
package com.oyhp.atom;
public class Test {
public static void main(String[] args) {
//总共5个糖果
GumballMachine gumballMachine = new GumballMachine(5);
System.out.println(gumballMachine);
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
System.out.println(gumballMachine);
gumballMachine.insertQuarter();
gumballMachine.ejectQuarter();
gumballMachine.turnCrank();
System.out.println(gumballMachine);
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.ejectQuarter();
System.out.println(gumballMachine);
gumballMachine.insertQuarter();
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
System.out.println(gumballMachine);
}
}
三、状态模式
1、状态接口
package com.oyhp.state;
//定义状态接口
public interface State {
public void insertQuarter();
public void ejectQuarter();
public void turnCrank();
public void dispense();
}
2、糖果机
package com.oyhp.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 State getWinnerState() {
return winnerState;
}
public int getCount() {
return count;
}
public void insertQuarter() {
state.insertQuarter();
}
public void ejectQuarter() {
state.ejectQuarter();
}
public void turnCrank() {
state.turnCrank();
}
public void dispense(){
state.dispense();
}
public void setState(State state){
this.state = state;
}
public void releaseBall(){
System.out.println("正在滚动糖果机售出糖果");
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;
}
@Override
public String toString() {
return "GumballMachine [state=" + state + ", count=" + count + "]";
}
}
3、五个状态
五种状态-五个类
package com.oyhp.state;
import java.util.Random;
public class HasQuarterState implements State{
Random randomWinner = new Random(System.currentTimeMillis());
GumballMachine gumballState;
public HasQuarterState(GumballMachine gumballMachine) {
this.gumballState = gumballMachine;
}
@Override
public void insertQuarter() {
System.out.println("已经投入25分钱,无法再投入");
}
@Override
public void ejectQuarter() {
System.out.println("25分钱退回");
//改变状态
gumballState.setState(gumballState.getNoQuarterState());
}
@Override
public void turnCrank() {
System.out.println("你正在转动曲柄......");
int winner = randomWinner.nextInt(10);
if((winner==0) && (gumballState.getCount() > 1)){
gumballState.setState(gumballState.getWinnerState());
}else{
gumballState.setState(gumballState.getSoldState());
}
}
@Override
public void dispense() {
System.out.println("需要先转动曲柄......");
}
}
package com.oyhp.state;
//没有25分钱
public class NoQuarterState implements State{
GumballMachine gumballMachine;
public NoQuarterState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
System.out.println("你投入了25分钱");
//改变状态
gumballMachine.setState(gumballMachine.getHasQuarterState());
}
@Override
public void ejectQuarter() {
System.out.println("你没有投入25分钱,无法退回");
}
@Override
public void turnCrank() {
System.out.println("你正在转动曲柄,但没有25分钱");
}
@Override
public void dispense() {
System.out.println("你需要先支付25分钱");
}
}
package com.oyhp.state;
public class SoldOutState implements State{
GumballMachine gumballMachine;
public SoldOutState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
System.out.println("无法投入糖果,糖果已售馨");
}
@Override
public void ejectQuarter() {
System.out.println("无法退回,糖果已售馨");
}
@Override
public void turnCrank() {
System.out.println("转动曲柄,糖果已售馨");
}
@Override
public void dispense() {
System.out.println("无法售出糖果,糖果已售馨");
}
}
package com.oyhp.state;
public class SoldState implements State{
GumballMachine gumballMachine;
public SoldState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
System.out.println("请等待,正在售出糖果......");
}
@Override
public void ejectQuarter() {
System.out.println("抱歉,正在售出糖果无法退回");
}
@Override
public void turnCrank() {
System.out.println("正在售出糖果");
}
@Override
public void dispense() {
//改变状态-售出糖果
gumballMachine.releaseBall();
if(gumballMachine.getCount() > 0){
gumballMachine.setState(gumballMachine.getNoQuarterState());
}else{
System.out.println("抱歉,糖果机已经售馨");
gumballMachine.setState(gumballMachine.getSoldOutState());
}
}
}
package com.oyhp.state;
public class WinnerState implements State{
GumballMachine gumballMachine;
public WinnerState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
throw new UnsupportedOperationException();
}
@Override
public void ejectQuarter() {
throw new UnsupportedOperationException();
}
@Override
public void turnCrank() {
throw new UnsupportedOperationException();
}
@Override
public void dispense() {
System.out.println("恭喜恭喜!你获得两颗糖果!");
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("糖果已经售馨");
gumballMachine.setState(gumballMachine.getSoldOutState());
}
}
}
}
4、测试
package com.oyhp.state;
public class GumballMachineTestDrive {
public static void main(String[] args) {
GumballMachine gumballMachine = new GumballMachine(5);
System.out.println(gumballMachine);
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.dispense();
System.out.println(gumballMachine);
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.dispense();
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.dispense();
System.out.println(gumballMachine);
}
}
四、状态模式类图
五、总结
1、状态模式允许一个对象基于内部状态而拥有不同的行为。
2、策略模式通过会用行为或算法来配置Context类。
3、状态模式允许Context随着状态的改变而改变行为
4、状态转换可以由State类或Context类控制
5、使用状态模式会导致设计中类的数目大量增加
6、状态类可以被多个Context实例共享