Java 设计模式(12) —— 状态模式
2018-05-22 本文已影响222人
磊_lei
一、状态模式
状态模式能根据内部状态的变化,改变对象的行为,看起来好像修改了类
二、示例
智能糖果机:需要设计一款自助购买的糖果机,糖果机的状态有
- 准备使用(接下来可投入硬币)
- 投入硬币(接下来可摇动把手或者退出硬币)
- 售出糖果(接下来可恢复使用或者售罄)
- 售罄状态
使用传统的面向对象模式,只需定义一个糖果机的对象,内部根据不同的状态进行不同的操作处理
/**
* 面向对象模式,糖果机
*/
public class CandyMachine {
final static int SoldOutState = 0; // 售罄状态
final static int OnReadyState = 1; // 准备售出状态
final static int HasCoin = 2; // 已经投了硬币的状态
final static int SoldState = 3; // 售出状态
private int state = SoldOutState;
private int count = 0; // 内部糖果的剩余数量
public CandyMachine(int count) {
this.count = count;
if (count > 0) {
state = OnReadyState;
}
}
/**
* 投入硬币,如果糖果机状态是准备售出,则可以摇动把手购买糖果,其他的状态则无法使用
*/
public void insertCoin() {
switch (state) {
case SoldOutState:
System.out.println("you can't insert coin,the machine sold out!");
break;
case OnReadyState:
state = HasCoin;
System.out
.println("you have inserted a coin,next,please turn crank!");
break;
case HasCoin:
System.out.println("you can't insert another coin!");
break;
case SoldState:
System.out.println("please wait!we are giving you a candy!");
break;
}
}
/**
* 如果已经投入硬币之后则可以选择退出硬币
*/
public void returnCoin() {
switch (state) {
case SoldOutState:
System.out
.println("you can't return,you haven't inserted a coin yet!");
break;
case OnReadyState:
System.out.println("you haven't inserted a coin yet!");
break;
case HasCoin:
System.out.println("coin return!");
state = OnReadyState;
break;
case SoldState:
System.out.println("sorry,you already have turned the crank!");
break;
}
}
/**
* 如果已经投入硬币则可以摇动把手
*/
public void turnCrank() {
switch (state) {
case SoldOutState:
System.out.println("you turned,but there are no candies!");
break;
case OnReadyState:
System.out.println("you turned,but you haven't inserted a coin!");
break;
case HasCoin:
System.out.println("crank turn...!");
state = SoldState;
dispense();
break;
case SoldState:
System.out.println("we are giving you a candy,turning another get nothing,!");
break;
}
}
/**
* 掉出糖果
*/
private void dispense() {
count--;
System.out.println("a candy rolling out!");
if (count > 0) {
state = OnReadyState;
} else {
System.out.println("Oo,out of candies");
state = SoldOutState;
}
}
public void printstate() {
switch (state) {
case SoldOutState:
System.out.println("***SoldOutState***");
break;
case OnReadyState:
System.out.println("***OnReadyState***");
break;
case HasCoin:
System.out.println("***HasCoin***");
break;
case SoldState:
System.out.println("***SoldState***");
break;
}
}
}
缺点:各种行为耦合度较高,不利于新需求的拓展
三、状态模式改进
虽然传统的面向对象模式也可满足功能,但是若新增需求则不利于拓展。加入此项目新增一个幸运者的功能,售出糖果的时候有一定几率成为幸运者掉出两颗糖果。
若满足该功能,则需在原本完成的糖果机代码中修改,则易造成其他不必要的bug,则引出状态模式:
- 定义一个状态接口,接口定义需要处理的方法
- 定义不同状态的接口对象,对象内实现不同状态对不同操作的处理
/**
* 状态模式,统一的状态接口,接口内实现不同状态下不同的处理行为
*/
public interface State {
// 投入硬币
public void insertCoin();
// 退出硬币
public void returnCoin();
// 摇动把手
public void turnCrank();
// 掉出糖果
public void dispense();
// 打印当前状态
public void printstate();
}
/**
* 状态模式,新增的幸运者状态,出糖果的时候有一定概率出两颗
*/
public class WinnerState implements State {
private CandyMachine mCandyMachine;
public WinnerState(CandyMachine mCandyMachine) {
this.mCandyMachine = mCandyMachine;
}
@Override
public void insertCoin() {
System.out.println("please wait!we are giving you a candy!");
}
@Override
public void returnCoin() {
System.out.println("you haven't inserted a coin yet!");
}
@Override
public void turnCrank() {
System.out.println("we are giving you a candy,turning another get nothing,!");
}
@Override
public void dispense() {
mCandyMachine.releaseCandy();
if (mCandyMachine.getCount() == 0) {
mCandyMachine.setState(mCandyMachine.mSoldOutState);
} else {
System.out.println("you are a winner!you get another candy!");
mCandyMachine.releaseCandy();
if (mCandyMachine.getCount() > 0) {
mCandyMachine.setState(mCandyMachine.mOnReadyState);
} else {
System.out.println("Oo,out of candies");
mCandyMachine.setState(mCandyMachine.mSoldOutState);
}
}
}
@Override
public void printstate() {
System.out.println("***WinnerState***");
}
}
/**
* 状态模式,糖果机内只定义状态接口对象,在接口内部给糖果机的状态赋值
*/
public class CandyMachine {
State mSoldOutState;
State mOnReadyState;
State mHasCoin;
State mSoldState;
State mWinnerState;
private State state;
private int count = 0;
public CandyMachine(int count) {
this.count = count;
mSoldOutState = new SoldOutState(this);
mOnReadyState = new OnReadyState(this);
mHasCoin = new HasCoin(this);
mSoldState = new SoldState(this);
mWinnerState = new WinnerState(this);
if (count > 0) {
state = mOnReadyState;
} else {
state = mSoldOutState;
}
}
public void setState(State state) {
this.state = state;
}
/**
* 糖果机的一切状态都直接调用状态接口内部的方法
*/
public void insertCoin() {
state.insertCoin();
}
public void returnCoin() {
state.returnCoin();
}
public void turnCrank() {
state.turnCrank();
state.dispense();
}
void releaseCandy() {
if (count > 0) {
count = count - 1;
System.out.println("a candy rolling out!");
}
}
public int getCount() {
return count;
}
public void printstate() {
state.printstate();
}
}
/**
* 状态模式,通过定义一个状态接口,接口内实现不同状态下不同的处理方式
* 则调用处理方式时直接调用状态接口对象的实现方法
* 使用状态模式可以是不同状态接互不影响,也可便于新增多种状态类型的需求
*/
public class MainTest {
public static void main(String[] args) {
CandyMachine mCandyMachine = new CandyMachine(6);
mCandyMachine.printstate();
mCandyMachine.insertCoin();
mCandyMachine.printstate();
mCandyMachine.turnCrank();
mCandyMachine.printstate();
mCandyMachine.insertCoin();
mCandyMachine.printstate();
mCandyMachine.turnCrank();
mCandyMachine.printstate();
}
}
四、总结
在很多情况下,一个对象的行为取决于一个或多个动态变化的属性,这样的属性叫做状态,这样的对象叫做有状态的(stateful)对象,这样的对象状态是从事先定义好的一系列值中取出的。当一个这样的对象与外部事件产生互动时,其内部状态就会改变,从而使得系统的行为也随之发生变化。
Java设计模式所有示例代码,持续更新中