美文网首页
Head First 设计模式 —— 12. 状态 (State

Head First 设计模式 —— 12. 状态 (State

作者: 满赋诸机 | 来源:发表于2021-01-15 21:06 被阅读0次

    思考题

    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

    • A. 这份代码确实没有遵守开放-关闭原则
      • 当新增状态时,必须在所有方法中加上对新状态的条件判断,所以没有遵守开放-关闭原则
    • B. 这份代码会让 Fortran 程序员感到骄傲
      • 不知道为什么
      • 【答案有此选项】
    • C. 这个设计其实不符合面向对象
      • 这个设计是面向过程的,所有的操作都通过条件判断,没有封装状态
    • D. 状态转换被埋藏在条件语句中,所以并不明显
      • 状态转换是在行为方法内的条件语句中,要找到状态转换前后的状态需要阅读行为方法内的全部代码,难以快速了解某种状态会如何转换
    • E. 我们还没有把会改变的那部分包起来
      • 状态和行为都会改变,但行为比较固定且与实际相对应,状态是抽象出来的,所以应该将状态封装起来
    • 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

    12. 状态模式

    特点

    • 将每个状态行为局部化到自己的状态类中 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
    状态模式:封装基于状态的行为,并将行为委托到当前状态
    策略模式:将可以互换的行为封装起来,然后使用委托的方法,决定使用哪一个行为
    模板方法模式:由子类决定如何实现算法中的某些步骤

    相关文章

      网友评论

          本文标题:Head First 设计模式 —— 12. 状态 (State

          本文链接:https://www.haomeiwen.com/subject/dwtgaktx.html