小王最近一直在寻找商机,他发现商场儿童乐园或者中小学校周围,会有很多小朋友喜欢吃糖果,那么他想设计一款糖果售卖机,让后将这些糖果售卖机布置到商场和学校旁边,这样就能获得源源不断的收益了。
想到这里,说干就干,他绘制出了一台糖果售卖机的操作及状态关系流转图,请见下图所示:
如果我们以动作做为一个方法去处理,比如:投入钱币的动作,那么我们就需要按照如下方式去实现方法中的逻辑:
【如果已经投了25分钱】提示“
已经投入钱币了,你不能再投入钱币了!
”; 【如果之前没有投过钱】提示“投入钱币成功!
”,并且当前的糖果机状态从未投币状态变为已投币状态; 【如果糖果机里无糖果】提示“糖果已经卖光了,你不能往里投入钱币了!
” 【如果糖果正在出货中】提示“请等一等,糖果正在出货中。你不用在投入钱币了!
”
针对以上逻辑,代码实现如下所示:
final?static?int?SOLD_OUT?=?0;?//?糖果售罄
final?static?int?NO_QUARTER?=?1;?//?没有投入钱币
final?static?int?HAS_QUARTER?=?2;?//?已经投入钱币
final?static?int?SOLD?=?3;?//?正在出售糖果
public?void?insertQuarter()?{
????if(state?==?HAS_QUARTER)?{
????????System.out.println("已经投入钱币了,你不能再投入钱币了");
????}?else?if(state?==?NO_QUARTER)?{
????????state?=?HAS_QUARTER;//?将糖果机的状态改为HAS_QUARTER(已投币)
????????System.out.println("投入钱币成功");
????}?if(state?==?SOLD_OUT)?{
????????System.out.println("糖果已经卖光了,你不能往里投入钱币了");
????}?if(state?==?SOLD)?{
????????System.out.println("请等一等,糖果正在出货中。你不用在投入钱币了");
????}
}
那么其他的动作,比例:转动曲柄、退回钱币操作、发放糖果等,也需要按照上面的写法去实现逻辑。显然,通过这么一大堆的if...else
是不优雅的,而且当增加一个全新的状态的时候,所有的动作都需要兼容这个新的动作,那么,这个就是很明显的基于过程编程了,针对以上的问题,我们可以使用今天要介绍的设计模式来解决——状态模式。
状态模式(State Pattern
)
允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。
状态模式和策略模式的区别——意图是不同的
【状态模式】随着时间流逝,当前状态在状态对象集合中游走改变,以反映出context内部的状态。客户对其基本不了解。它是针对具有很多条件判断的替代方案。 【策略模式】客户通常主动指定context索要组合的策略对象是哪一个。它是继承之外的一种弹性替代方案。
针对上面的介绍,我们来构造一下状态模式的类图,首先,创建状态接口State.java
,接口里面包含了“插入硬币
”、“退出硬币
”、“扭转曲柄
”和“发放糖果
”这四个操作,那么具体的动作实现逻辑是与不同状态实现类一一对应的,也就是说,不同状态实现类负责各自的四个动作方法的具体实现。针对状态接口,我们创建4个实现类,分别是:糖果售卖状态类SoldState.java
、糖果售空状态类SoldOutState.java
、已经投放钱币状态类HasQuarterState.java
、没有投放钱币状态类NoQuarterState.java
,那么当前处于哪个状态则由糖果售卖机类GumballMachine.java
维护。具体类图请见下图所示:
状态接口类:State.java
public?interface?State?{
????void?insertQuarter();?//?投入硬币操作???
????void?ejectQuarter();?//?退出硬币操作
????void?turnCrank();?//?扭转曲柄操作
????void?dispense();?//?发放糖果操作
}
糖果售卖状态类:SoldState.java
public?class?SoldState?implements?State?{
????private?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()?{
????????if?(gumballMachine.getCount()?>?0)?{
????????????System.out.println("糖果正在出货中,请稍等!");
????????????gumballMachine.releaseBall();
????????????gumballMachine.setState(gumballMachine.getNoQuarterState());?//?状态流转
????????}?else?{
????????????System.out.println("糖果库存不足,无法出货!");
????????????gumballMachine.setState(gumballMachine.getSoldOutState());?//?状态流转
????????}
????}
}
糖果售空状态类:SoldOutState.java
public?class?SoldOutState?implements?State?{
????private?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("糖果已经售罄。糖果无法出售!");
????}
}
已经投放钱币状态类:HasQuarterState.java
public?class?HasQuarterState?implements?State?{
????private?GumballMachine?gumballMachine;
????public?HasQuarterState(GumballMachine?gumballMachine)?{
????????this.gumballMachine?=?gumballMachine;
????}
????@Override
????public?void?insertQuarter()?{
????????System.out.println("您已经投入钱币!无须再次投入钱币!");
????}
????@Override
????public?void?ejectQuarter()?{
????????System.out.println("退款成功!");
????????gumballMachine.setState(gumballMachine.getNoQuarterState());?//?状态流转
????}
????@Override
????public?void?turnCrank()?{
????????System.out.println("正在出货中,请稍等");
????????gumballMachine.setState(gumballMachine.getSoldState());?//?状态流转
????}
????@Override
????public?void?dispense()?{
????????System.out.println("你还没有扭转曲柄,糖果不可以发放!");
????}
}
没有投放钱币状态类:NoQuarterState.java
public?class?NoQuarterState?implements?State?{
????private?GumballMachine?gumballMachine;
????public?NoQuarterState(GumballMachine?gumballMachine)?{
????????this.gumballMachine?=?gumballMachine;
????}
????@Override
????public?void?insertQuarter()?{
????????System.out.println("投入钱币成功!");
????????gumballMachine.setState(gumballMachine.getHasQuarterState());?//?状态流转
????}
????@Override
????public?void?ejectQuarter()?{
????????System.out.println("你还没有投入钱币,不能退回钱币!");
????}
????@Override
????public?void?turnCrank()?{
????????System.out.println("你还没有投入钱币,不能扭转曲柄!");
????}
????@Override
????public?void?dispense()?{
????????System.out.println("你还没有投入钱币,糖果不可以发放!");
????}
}
糖果售卖机类:GumballMachine.java
@Data
public?class?GumballMachine?{
????private?State?noQuarterState;
????private?State?hasQuarterState;
????private?State?soldState;
????private?State?soldOutState;
????private?State?state?=?soldOutState;?//?糖果机默认状态为售罄状态
????int?count?=?0;?//?糖果库存量
????public?GumballMachine(int?numberGumballs)?{
????????noQuarterState?=?new?NoQuarterState(this);
????????hasQuarterState?=?new?HasQuarterState(this);
????????soldState?=?new?SoldState(this);
????????soldOutState?=?new?SoldOutState(this);
????????count?=?numberGumballs;
????????if?(numberGumballs?>?0)?{
????????????state?=?noQuarterState;?//?如果采购了糖果球(numberGumballs>0),则糖果机的状态为未投币状态
????????}
????}
????//?投入钱币
????public?void?insertQuarter()?{
????????state.insertQuarter();
????}
????//?退出钱币
????public?void?ejectQuarter()?{
????????state.ejectQuarter();
????}
????//?扭转曲柄
????public?void?turnCrank()?{
????????state.turnCrank();
????????state.dispense();
????}
????//?减少库存
????public?void?releaseBall()?{
????????if?(count?>?0)?{
????????????System.out.println("一个糖果球正在出库");
????????????--count;
????????}?else?{
????????????System.out.println("库存不足,一个糖果球无法出库");
????????}
????}
????//?设置状态
????void?setState(State?state)?{
????????this.state?=?state;
????}
}
状态模式测试类:StateTest.java
public?class?StateTest?{
????public?static?void?main(String[]?args)?{
????????System.out.println("-----向糖果机中放入1枚糖果-----");
????????GumballMachine?machine?=?new?GumballMachine(1);
????????System.out.println("-----第一次购买糖果-----");
????????machine.insertQuarter();
????????machine.ejectQuarter();
????????machine.turnCrank();
????????System.out.println("-----第二次购买糖果-----");
????????machine.insertQuarter();
????????machine.turnCrank();
????????System.out.println("-----第三次购买糖果-----");
????????machine.insertQuarter();
????????machine.turnCrank();
????????machine.ejectQuarter();
????}
}
今天的文章内容就这些了:
写作不易,笔者几个小时甚至数天完成的一篇文章,只愿换来您几秒钟的 点赞 & 分享 。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。