1.场景问题解决
1.1 场景描述
糖果售卖机,状态有售完0,待机1,已投币2,给糖果3.
1.2 OO设计
- 糖果售卖机
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 = count - 1;
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;
}
}
}
- MainTest 测试类
public class MainTest {
public static void main(String[] args) {
CandyMachine mCandyMachine=new CandyMachine(1);
mCandyMachine.printstate();
mCandyMachine.insertCoin();
mCandyMachine.printstate();
mCandyMachine.turnCrank();
mCandyMachine.printstate();
mCandyMachine.insertCoin();
mCandyMachine.printstate();
mCandyMachine.turnCrank();
mCandyMachine.printstate();
}
}
1.3 需求变动
加入游戏元素:有10%的概率可以拿到2粒糖果,会多了一个状态"中奖".
1.4 带来问题
加入一个状态后,状态的组合会增加许多,并且如果修改会修改之前的逻辑,修改代码较多.
2.用设计模式改进
状态改变但是行为不改变,所有可以把状态封装为对象,状态中封装了动作/行为.
2.1 分析
2.2 重新设计
[外链图片转存失败(img-jCbNZuev-1566575835237)(https://github.com/bobshute/public/blob/master/imgs/csdn/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/12%E7%8A%B6%E6%80%81%E6%A8%A1%E5%BC%8F-1%E7%B1%BB%E5%9B%BE.png?raw=true)]
2.3 源码
- interface State
public interface State {
//插入硬币
public void insertCoin();
//返回硬币
public void returnCoin();
//转动曲柄
public void turnCrank();
//分发糖果
public void dispense();
//打印状态
public void printstate();
}
- SoldOutState、HasCoin、OnReadyState、SoldState、 WinnerState 各状态实现State接口
public class SoldOutState implements State {
private CandyMachine mCandyMachine;
public SoldOutState(CandyMachine mCandyMachine)
{
this.mCandyMachine=mCandyMachine;
}
@Override
public void insertCoin() {
System.out.println("you can't insert coin,the machine sold out!");
}
@Override
public void returnCoin() {
System.out.println("you can't return,you haven't inserted a coin yet!");
}
@Override
public void turnCrank() {
System.out.println("you turned,but there are no candies!");
}
@Override
public void dispense() {
}
@Override
public void printstate() {
System.out.println("***SoldOutState***");
}
}
- CandyMachine糖果机
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 StateTest {
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();
}
}
3.设计模式总结
3.1 定义
***状态模式***能根据内部状态的变化,改变对象的行为,看起来好像修改了类
3.2 分析思路
状态是可变的,但是行为是固定的.
所以将状态定义为接口可变,接口中有行为是固定的,然后各种具体状态实现该状态接口,在各状态对象中处理各种行为是否可行.
状态对象中对修改的关闭,对功能的扩展.
4. 设计模式使用场景及注意
5.参考文章
内容总计于HeadFirst设计模式及相关视频