思考题
public class GumballMachine { final static int SOLD_OUT = 0; final static int NO_QUARTER = 1; final static int HAS_QUARTER = 2; final static SOLD = 3; int state = SOLD_OUT; int count = 0; public GumballMachine(int count) { this.count = count; if(count > 0) { state = NO_QUARTER; } } public void insertQuarter() { if(state == HAS_QUARTER) { // print error message } else if(state == NO_QUARTER) { state = HAS_QUARTER; // print success message } else if(state == SOLD_OUT) { // print error message } else if(state == SOLD) { // print error message } } public void ejectQuarter() { // ... } public void turnCrank() { // ... } public void dispense() { // ... }}
下列哪一项形容了咱们实现的状态?(多选) P396
[x] A. 这份代码的确没有恪守凋谢-敞开准则
- 当新增状态时,必须在所有办法中加上对新状态的条件判断,所以没有恪守凋谢-敞开准则
[ ] B. 这份代码会让 Fortran 程序员感到自豪
- 不晓得为什么
- 【答案有此选项】
[x] C. 这个设计其实不合乎面向对象
- 这个设计是面向过程的,所有的操作都通过条件判断,没有封装状态
[x] D. 状态转换被埋藏在条件语句中,所以并不显著
- 状态转换是在行为办法内的条件语句中,要找到状态转换前后的状态须要浏览行为办法内的全副代码,难以疾速理解某种状态会如何转换
[x] E. 咱们还没有把会扭转的那局部包起来
- 状态和行为都会扭转,但行为比拟固定且与理论绝对应,状态是形象进去的,所以应该将状态封装起来
[x] F. 将来退出的代码很有可能会导致 bug
- 因为所有行为办法内都有不同状态的条件判断,所以在任何状态发生变化时,都要对所有行为办法进行批改进行解决,很容易忘记对某行为办法的批改
思考题
public class GumballMachine { State soldOutState; State noQuarterState; State hasQuarterState; State soldState; 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); 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; } void releaseBall() { // print success message if(count != 0) { count = count - 1; } }}
让咱们来回头看看糖果机的实现。如果曲柄被转动了,然而没有胜利(比方说顾客没有先投入25分钱的硬币)。在这种状况下,只管没有必要,但咱们还是会调用 dispense()
办法。对于这个问题你要如何批改呢? P405
State
接口的turnCrank()
办法减少返回值以示意是否正确处理,只有在正确处理时,才调用dispense()
办法
状态模式
容许对象在外部状态扭转时扭转它的行为,对象看起来如同批改了它的类。 P410
特点
- 将每个状态行为部分化到本人的状态类中
P407
- 让每个状态“对批改更换比”,让上下文“对扩大凋谢”,因为能够退出新的状态类
P407
毛病
- 通常会导致设计中类的数目大量减少
P423
状态模式和策略模式的区别
状态模式
- 将一群行为封装在状态对象中,上下文的行为随时可委托到那些状态对象中的一个。以后状态会在状态对象汇合中游走扭转,以反馈出上下文外部的状态,因而,上下文的行为也会跟着扭转。但时客户对于上下文的状态对象理解不多,甚至基本是浑然不知
P411
- 是不必在上下文中搁置许多条件判断的代替计划,通过将行为包装进状态对象中,在上下文内简略地扭转状态对象来扭转上下文的行为
P411
策略模式
- 客户通常被动指定上下文所要组合的策略对象
P411
- 是除继承之外的一种弹性代替计划,能够通过组合不同的对象来扭转行为
P411
思考题
应该由状态类还是上下文决定状态转换的流向? P412
- 当状态转换是固定的时候,适宜放在上下文中(此时状态类之间不相互依赖,是对状态类批改关闭)
P412
- 当状态转换是更动静的时候,通常就会放在状态类中(此时状态类之间产生了依赖,是对上下文批改关闭)
P412
思考题
咱们须要你为糖果机写一个重填糖果的 refill()
办法。这个办法须要一个变量——所要填入机器中的糖果数目。它应该能更新糖果机内的糖果数目,并重设机器的状态。 P421
void refill(int num) { this.count += num; if(state instanceof SoldOutState) { state = noQuarterState; }}
思考题
配对下列模式和形容: P422
状态模式:封装基于状态的行为,并将行为委托到以后状态
策略模式:将能够调换的行为封装起来,而后应用委托的办法,决定应用哪一个行为
模板办法模式:由子类决定如何实现算法中的某些步骤
本文首发于公众号:满赋诸机(点击查看原文) 开源在 GitHub :reading-notes/head-first-design-patterns