`
liuhui998
  • 浏览: 101524 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

State Pattern 状态模式(From head first pattern)

阅读更多

最近因为要用state pattern,于是在看Head First设计模式 看完之后,google一下发现了 http://www.blogjava.net/deep2/archive/2008/07/18/215613.html 就转了过来:) 相当于做一个记号吧 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 

一个糖果机,有四个状态,状态图如下:

最基本的实现思路如下:用四个整型数表示四种状态,用四个函数表达四个操作,每次进行操作的时候都要判断一下是否处于可进行这步操作的状态,操作完成后,需要更新状态到下一步。

package javaapplication41;

public class Main {

    public static void main(String[] args) {

        GumballMachine gm = new GumballMachine();

        gm.addGumballsToMachine(2);

        gm.insertQuarter();

        gm.turnsCrank();

        System.out.println("------------------");

        gm.insertQuarter();

        gm.insertQuarter();

        gm.turnsCrank();

        gm.ejectQuarter();

        gm.turnsCrank();

    }

}

class GumballMachine {

    final int SOLD_OUT = 0;

    final int NO_QUARTER = 1;

    final int HAS_QUARTER = 2;

    final int SOLD = 3;

    int state;

    int gumballs = 0;

    public GumballMachine() {

        state = SOLD_OUT;

    }

    public void insertQuarter() {

        if (state == NO_QUARTER) {

            System.out.println("inserting the quarter");

            state = HAS_QUARTER;

        }

        else if (state == HAS_QUARTER) {

            System.out.println("already has the quarter");

        }

        else if (state == SOLD) {

            System.out.println("already has the quarter and have turn the crank");

        }

        else if (state == SOLD_OUT) {

            System.out.println("there is no gumballs in the machine");

        }

    }

    public void ejectQuarter() {

        if (state == HAS_QUARTER) {

            System.out.println("ejecting the quarter....");

            state = NO_QUARTER;

        }

        else if (state == NO_QUARTER) {

            System.out.println("you haven't insert the quarter");

        }

        else if (state == SOLD) {

            System.out.println("already has the quarter and have turn the crank");

        }

        else if (state == SOLD_OUT) {

            System.out.println("there is no gumballs in the machine");

        }

    }

    public void turnsCrank() {

        if (state == HAS_QUARTER) {

            System.out.println("turning on the crank");

            state = SOLD;

            dispense();           

        }

        else if (state == NO_QUARTER) {

            System.out.println("you haven't insert the quarter");

        }

        else if (state == SOLD) {

            System.out.println("already has the quarter and have turn the crank");

        }

        else if (state == SOLD_OUT) {

            System.out.println("there is no gumballs in the machine");

        }

    }

    private void dispense() {

        if (state == SOLD) {

            if (gumballs == 0) {

                System.out.println("out of gumballs");

                state = SOLD_OUT;

            }

            else {

                System.out.println("dispensing the gumball");

                gumballs--;

                System.out.println("there are " + gumballs + " gumballs in the machine.");

                state = NO_QUARTER;

            }

        }

        else if (state == NO_QUARTER) {

            System.out.println("you haven't insert the quarter");

        }

        else if (state == HAS_QUARTER) {

            System.out.println("you haven't turn the crank");

        }

        else if (state == SOLD_OUT) {

            System.out.println("there is no gumballs in the machine");

        }

    }

    public void addGumballsToMachine(int num) {

        gumballs += num;

        System.out.println("adding " + num + " gumballs to the machine.");

        System.out.println("there are " + gumballs + " gumballs in the machine.");

        System.out.println("--------------------");

        if (gumballs > 0) {

            state = NO_QUARTER;

        }

    }

}

现在添加一个新的流程:当turns crank的时候,判断是否为1/10概率产生的幸运儿,如果是,则弹出两个糖果,如果不是,则仍弹出一个糖果。


实现如下:

package javaapplication41;

public class Main {

    public static void main(String[] args) {

        GumballMachine gm = new GumballMachine();

        gm.addGumballsToMachine(2);

        gm.insertQuarter();

        gm.turnsCrank();

        System.out.println("------------------");

        gm.insertQuarter();

        gm.insertQuarter();

        gm.turnsCrank();

        gm.ejectQuarter();

        gm.turnsCrank();

    }

}

class GumballMachine {

    final int SOLD_OUT = 0;

    final int NO_QUARTER = 1;

    final int HAS_QUARTER = 2;

    final int SOLD = 3;

    final int SOLD_TO_WINNER = 4;

    int state;

    int gumballs = 0;

    public GumballMachine() {

        state = SOLD_OUT;

    }

    public void insertQuarter() {

        if (state == NO_QUARTER) {

            System.out.println("inserting the quarter");

            state = HAS_QUARTER;

        }

        else if (state == HAS_QUARTER) {

            System.out.println("already has the quarter");

        }

        else if (state == SOLD) {

            System.out.println("already has the quarter and have turn the crank");

        }

        else if (state == SOLD_OUT) {

            System.out.println("there is no gumballs in the machine");

        }

        else if (state == SOLD_TO_WINNER) {

            System.out.println("already has the quarter and have turn the crank");

        }

    }

    public void ejectQuarter() {

        if (state == HAS_QUARTER) {

            System.out.println("ejecting the quarter....");

            state = NO_QUARTER;

        }

        else if (state == NO_QUARTER) {

            System.out.println("you haven't insert the quarter");

        }

        else if (state == SOLD) {

            System.out.println("already has the quarter and have turn the crank");

        }

        else if (state == SOLD_OUT) {

            System.out.println("there is no gumballs in the machine");

        }

        else if (state == SOLD_TO_WINNER) {

            System.out.println("already has the quarter and have turn the crank");

        }

    }

    public void turnsCrank() {

        if (state == HAS_QUARTER) {

            System.out.println("turning on the crank");

            state = SOLD;

            dispense();

        }

        else if (state == NO_QUARTER) {

            System.out.println("you haven't insert the quarter");

        }

        else if (state == SOLD) {

            System.out.println("already has the quarter and have turn the crank");

        }

        else if (state == SOLD_OUT) {

            System.out.println("there is no gumballs in the machine");

        }

        else if (state == SOLD_TO_WINNER) {

            System.out.println("already has the quarter and have turn the crank");

        }

    }

    private void dispense() {

        if (state == SOLD) {

            if (gumballs == 0) {

                System.out.println("out of gumballs");

                state = SOLD_OUT;

            }

            else {

                System.out.println("dispensing the gumball");

                gumballs--;

                System.out.println("there are " + gumballs + " gumballs in the machine.");

                state = NO_QUARTER;

            }

        }

        else if (state == SOLD_TO_WINNER) {

            if (gumballs == 0) {

                System.out.println("out of gumballs");

                state = SOLD_OUT;

            }

            else if (gumballs == 1) {

                System.out.println("dispensing the gumball");

                gumballs--;

                System.out.println("there are " + gumballs + " gumballs in the machine.");

                state = SOLD_OUT;

            }

            else if (gumballs > 1) {

                System.out.println("dispensing the 2 gumballs");

                gumballs -= 2;

                System.out.println("there are " + gumballs + " gumballs in the machine.");

                state = NO_QUARTER;

            }

        }

        else if (state == NO_QUARTER) {

            System.out.println("you haven't insert the quarter");

        }

        else if (state == HAS_QUARTER) {

            System.out.println("you haven't turn the crank");

        }

        else if (state == SOLD_OUT) {

            System.out.println("there is no gumballs in the machine");

        }

    }

    public void addGumballsToMachine(int num) {

        gumballs += num;

        System.out.println("adding " + num + " gumballs to the machine.");

        System.out.println("there are " + gumballs + " gumballs in the machine.");

        System.out.println("--------------------");

        if (gumballs > 0) {

            state = NO_QUARTER;

        }

    }

}

可见,为了添加一个流程,我们首先需要添加一个状态SOLD_TO_WINNER = 4,然后在每个流程里面都要判断一下是否处于这个状态,故而每个流程都添加了一个else if….

这样的代码,维护起来是可怕的,也就是说,这样的设计思路是不易于扩展的。

看到上面的程序,让我想到了以前写的“邮件收发程序”,繁复的else if…判断语句让我修改到最后,实在连看都不想看!不过好了,现在有了state pattern,专门处理怎样写业务流程。

State Pattern 的前提条件是:经常发生改变的是状态(也就是业务流程),而不是“操作”。在上面的例子中,我们把四个“操作”写成了类,但发生变化的不是操作,而是if…else中的状态。所以反其道而行之,我们把各个状态写成类(把易变化的隔离的单独的类里面去)。如下:(未增加新状态前)

package javaapplication42;

public class Main {

    public static void main(String[] args) {

        GumballMachine gm = new GumballMachine();

        gm.addGumballs(2);

        gm.state.insertQuarter();//并没有指明是哪种状态,全部都用state,这就是代理

        gm.state.turnCrank();

        gm.state.insertQuarter();

        gm.state.ejectQuarter();

        gm.state.turnCrank();

        gm.state.insertQuarter();

        gm.state.insertQuarter();

        gm.state.turnCrank();

        gm.state.insertQuarter();

        gm.state.turnCrank();

        gm.addGumballs(1);

        gm.state.insertQuarter();

        gm.state.turnCrank();

    }

}

interface State { //四个状态都继承它,这样我们可以“代理”,每个状态都有如下四个操作。

    public void insertQuarter();

    public void ejectQuarter();

    public void turnCrank();

    public void dispense();

}

class GumballMachine {

    State state;

    State noQuarterState;

    State hasQuarterState;

    State soldState;

    State soldOutState;

    int gumballNum;//机器内糖果的数量

    public GumballMachine() {

        noQuarterState = new NoQuarterState(this);

        hasQuarterState = new HasQuarterState(this);

        soldState = new SoldState(this);

        soldOutState = new SoldOutState(this);

        this.state = soldOutState;//initialize "state",这个state将贯穿整个执行过程

        gumballNum = 0;

    }

    public void setState(State state) {

        this.state = state;

    }

    public void play() {

        state.insertQuarter();

        state.turnCrank();

        state.dispense();

    }

    public void addGumballs(int num) {

        gumballNum += num;

        if (gumballNum > 0) {

            this.state = noQuarterState;

        }

        System.out.println("the machine has "+gumballNum+" gumball(s)");

    }

}

class NoQuarterState implements State {

    GumballMachine gm;

    public NoQuarterState(GumballMachine gm) {

        this.gm = gm;

    }

    public void insertQuarter() {

       System.out.println("insert a quarter...");

        gm.setState(gm.hasQuarterState);//执行完后,改变状态

    }

    public void ejectQuarter() {

        System.out.println("you can't eject quarter, for you haven't insert yet 1");

    }

    public void turnCrank() {

        System.out.println("you can't turn crank, for you haven't insert yet 2");

    }

    public void dispense() {

        System.out.println("you can't dispense, for you haven't insert yet 3");

    }

}

class HasQuarterState implements State {

    GumballMachine gm;

    public HasQuarterState(GumballMachine gm) {

        this.gm = gm;

    }

    public void insertQuarter() {

        System.out.println("you can't insert quarter, for you have insert one already");

    }

    public void ejectQuarter() {

        System.out.println("eject quarter...");

        gm.setState(gm.noQuarterState);

    }

    public void turnCrank() {

        System.out.println("turning the crank...");

        gm.setState(gm.soldState);

        gm.state.dispense();

    }

    public void dispense() {

        System.out.println("when you turn the crank, the machine will dispense the gumball");

    }

}

class SoldState implements State {

    GumballMachine gm;

    public SoldState(GumballMachine gm) {

        this.gm = gm;

    }

    public void insertQuarter() {

        throw new UnsupportedOperationException("Not supported yet.");

    }

    public void ejectQuarter() {

        throw new UnsupportedOperationException("Not supported yet.");

    }

    public void turnCrank() {

        throw new UnsupportedOperationException("Not supported yet.");

    }

    public void dispense() {

        gm.gumballNum--;

        System.out.println("dispense one gumball...");

        if (gm.gumballNum > 0) {

            gm.setState(gm.noQuarterState);

        }

        else {

            System.out.println("Machine has no gumball");

            gm.setState(gm.soldOutState);

        }

    }

}

class SoldOutState implements State {

    GumballMachine gm;

    public SoldOutState(GumballMachine gm) {

        this.gm = gm;

    }

    public void insertQuarter() {

        System.out.println("you can't insert quarter, for the machine has no gumball");

    }

    public void ejectQuarter() {

        System.out.println("you can't eject quarter, for the machine has no gumball");

    }

    public void turnCrank() {

        System.out.println("you can't turn crank, for the machine has no gumball");

    }

    public void dispense() {

        System.out.println("you can't dispense, for the machine has no gumball");

    }

}

现在,我们新增SoldToWinnerState流程(1/10的概率获得两个gumball):

package javaapplication42;

import java.util.Random;

public class Main {

    public static void main(String[] args) {

        GumballMachine gm = new GumballMachine();

        gm.addGumballs(2);

        gm.state.insertQuarter();

        gm.state.turnCrank();

        gm.state.insertQuarter();

        gm.state.ejectQuarter();

        gm.state.turnCrank();

        gm.state.insertQuarter();

        gm.state.insertQuarter();

        gm.state.turnCrank();

        gm.state.insertQuarter();

        gm.state.turnCrank();

        gm.addGumballs(1);

        gm.state.insertQuarter();

        gm.state.turnCrank();

    }

}

interface State {

    public void insertQuarter();

    public void ejectQuarter();

    public void turnCrank();

    public void dispense();

}

class GumballMachine {

    State state;

    State noQuarterState;

    State hasQuarterState;

    State soldState;

    State soldOutState;

    State soldToWinnerState;

    int gumballNum;//机器内糖果的数量

    public GumballMachine() {

        noQuarterState = new NoQuarterState(this);

        hasQuarterState = new HasQuarterState(this);

        soldState = new SoldState(this);

        soldOutState = new SoldOutState(this);

        soldToWinnerState = new SoldToWinnerState(this);

        this.state = soldOutState;//initialize "state",这个state将贯穿整个执行过程

        gumballNum = 0;

    }

    public void setState(State state) {

        this.state = state;

    }

    public void play() {

        state.insertQuarter();

        state.turnCrank();

        state.dispense();

    }

    public void addGumballs(int num) {

        gumballNum += num;

        if (gumballNum > 0) {

            this.state = noQuarterState;

        }

        System.out.println("the machine has " + gumballNum + " gumball(s)");

    }

}

class SoldToWinnerState implements State {

    GumballMachine gm;

    public SoldToWinnerState(GumballMachine gm) {

        this.gm = gm;

    }

    public void insertQuarter() {

        System.out.println("you have insert one quarter already");

    }

    public void ejectQuarter() {

        System.out.println("you have turn crank already");

    }

    public void turnCrank() {

        System.out.println("you have turn crank already");

    }

    public void dispense() {

        gm.gumballNum -= 2; //具体细节,比如机器里只有一个糖果,暂不考虑,不是重点

        System.out.println("*************you are winner!************");

        System.out.println("dispense two gumball...");

        if (gm.gumballNum > 0) {

            gm.setState(gm.noQuarterState);

        }

        else {

            System.out.println("Machine has no gumball");

            gm.setState(gm.soldOutState);

       }

    }

}

class NoQuarterState implements State {

    GumballMachine gm;

    public NoQuarterState(GumballMachine gm) {

        this.gm = gm;

    }

    public void insertQuarter() {

        System.out.println("insert a quarter...");

        gm.setState(gm.hasQuarterState);

    }

    public void ejectQuarter() {

        System.out.println("you can't eject quarter, for you haven't insert yet 1");

    }

    public void turnCrank() {

        System.out.println("you can't turn crank, for you haven't insert yet 2");

    }

    public void dispense() {

        System.out.println("you can't dispense, for you haven't insert yet 3");

    }

}

class HasQuarterState implements State {

    Random rm;

    GumballMachine gm;

    public HasQuarterState(GumballMachine gm) {

        this.gm = gm;

        rm = new Random();

    }

    public void insertQuarter() {

        System.out.println("you can't insert quarter, for you have insert one already");

    }

    public void ejectQuarter() {

        System.out.println("eject quarter...");

        gm.setState(gm.noQuarterState);

    }

    public void turnCrank() {

        System.out.println("turning the crank...");

        if (rm.nextFloat() * 10 == 9) { //产生0-9之间的随机数

            gm.setState(gm.soldToWinnerState);

        }

        else {

            gm.setState(gm.soldState);

        }

        gm.state.dispense();

    }

    public void dispense() {

        System.out.println("when you turn the crank, the machine will dispense the gumball");

    }

}

class SoldState implements State {

    GumballMachine gm;

    public SoldState(GumballMachine gm) {

        this.gm = gm;

    }

    public void insertQuarter() {

        throw new UnsupportedOperationException("Not supported yet.");

    }

    public void ejectQuarter() {

        throw new UnsupportedOperationException("Not supported yet.");

    }

    public void turnCrank() {

        throw new UnsupportedOperationException("Not supported yet.");

    }

    public void dispense() {

        gm.gumballNum--;

        System.out.println("dispense one gumball...");

        if (gm.gumballNum > 0) {

            gm.setState(gm.noQuarterState);

        }

        else {

            System.out.println("Machine has no gumball");

            gm.setState(gm.soldOutState);

        }

    }

}

class SoldOutState implements State {

    GumballMachine gm;

    public SoldOutState(GumballMachine gm) {

        this.gm = gm;

    }

    public void insertQuarter() {

        System.out.println("you can't insert quarter, for the machine has no gumball");

    }

    public void ejectQuarter() {

        System.out.println("you can't eject quarter, for the machine has no gumball");

    }

    public void turnCrank() {

        System.out.println("you can't turn crank, for the machine has no gumball");

    }

    public void dispense() {

        System.out.println("you can't dispense, for the machine has no gumball");

    }

}

可见,在state pattern中,新增一个状态,只需要新增一个(表达这个状态的)类,并在该状态的“上游状态”做少许改动即可。
 

  • 大小: 34.1 KB
  • 大小: 28.2 KB
  • 大小: 76.1 KB
  • 大小: 49.3 KB
分享到:
评论

相关推荐

    Head First 设计模式 (十) 状态模式(State pattern) C++实现

    状态模式是一种行为设计模式,它允许对象在内部状态改变时改变其行为,对象看起来似乎修改了它的类。...在Head First的书籍中,这种模式通常通过生动的示例和图解进行解释,帮助读者更好地理解和应用到实际项目中。

    Head First Design Pattern

    例如策略模式(Strategy)、模板方法模式(Template Method)、观察者模式(Observer)、命令模式(Command)、迭代器模式(Iterator)、访问者模式(Visitor)、备忘录模式(Memento)、状态模式(State)、职责链...

    Head First设计模式 源代码

    - 状态模式(State Pattern):允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。 - 策略模式(Strategy Pattern):定义了一系列的算法,并将每一个算法封装起来,使它们可以互相替换。...

    HeadFirst设计模式英文版

    《Head First 设计模式》的英文版是一本面向初学者的设计模式入门书籍,它以幽默风趣的文风,深入浅出地介绍了软件设计中经常使用的设计模式。设计模式是一套被反复使用、多数人知晓、经过分类编目、代码设计经验的...

    Head First design pattern非扫描版原生版

    11. **状态模式(State)**:状态模式允许对象在其内部状态改变时改变其行为,对象看起来似乎修改了它的类。这种模式常用于处理对象状态变化引起的行为变化。 12. **职责链模式(Chain of Responsibility)**:职责...

    head first设计模式学习代码

    我们来看"DesignPattern"这个目录,它可能包含了23种常见的设计模式示例代码,如单例模式、工厂模式、抽象工厂模式、建造者模式、装饰器模式、适配器模式、桥接模式、组合模式、享元模式、代理模式、命令模式、职责...

    HeadFirst Design Pattern

    如策略模式(Strategy)、模板方法模式(Template Method)、观察者模式(Observer)、迭代器模式(Iterator)、命令模式(Command)、备忘录模式(Memento)、状态模式(State)、访问者模式(Visitor)、解释器...

    Head first design pattern

    又如,使用门卫和访客的场景来阐述状态模式(State),演示了对象行为如何随着内部状态的改变而变化。 《Head First设计模式》不仅介绍了23个GOF(GoF,Gang of Four)经典设计模式,还讨论了模式在实际项目中的...

    Observer HeadFirst design pattern

    在"Observer HeadFirst design pattern"中,作者通过生动的比喻和互动式的例子,帮助读者深入理解观察者模式的核心概念和实现方式。 观察者模式的核心思想是将"主题"(Subject)与"观察者"(Observer)解耦,主题...

    《HeadFirst设计模式》平时实验源代码和实验报告

    《HeadFirst设计模式》是一本深受开发者喜爱的设计模式学习书籍,以其独特的教学方式,通过丰富的图解和幽默的语言,使得复杂的设计模式概念变得易于理解。这本书涵盖了23种经典的GoF设计模式,以及一些现代软件开发...

    Head First 设计模式

    11. **状态模式(State Pattern)**:允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。 12. **代理模式(Proxy Pattern)**:为其他对象提供一个代用品或占位符,以控制对这个对象的访问,通常...

    Head First Design Patterns 随书附带源代码

    《Head First Design Patterns》是设计模式领域内一本非常知名的书籍,以其独特的教学方式深受程序员喜爱。这本书通过生动、直观的方式讲解了23种经典的设计模式,帮助开发者提升软件设计能力和可维护性。随书附带的...

    《HeadFirst设计模式》观察者模式c++实现代码

    观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。 Observer Pattern defines a one-to-many dependency between objects so that when one object ...

    Head First 设计模式学习笔记(十四)模式的组合使用

    6. **状态模式(State Pattern)**:Duck对象可能根据其当前状态(如飞、叫等)执行不同的行为,这可能是状态模式的应用。状态模式允许一个对象在其内部状态改变时改变它的行为,对象看起来好像修改了它的类。 通过...

    HeadFirstDesignPattern(深入浅出设计模式)源码

    源码包中的"headfirst"文件包含了书中各个设计模式的实现,下面将对这些知识点进行详细解释。 1. **单例模式** (Singleton): 这个模式确保一个类只有一个实例,并提供全局访问点。在"headfirst"中,你可以看到如何...

    Head First Design Patterns英文版

    13. 状态模式(State Pattern):允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。 14. 策略模式(Strategy Pattern):定义了一系列的算法,并将每一个算法封装起来,使得它们可以互相...

    head first design patterns 英文原版高清

    《Head First设计模式》是一本深入浅出讲解软件设计模式的书籍,作者是Eric Freeman、Elisabeth Freeman、Bert Bates和Kathy Sierra。本书共包含14章内容,每章介绍了一些设计模式,覆盖了四人组(Gang of Four, GoF...

    Head-First-Design-Patterns-master设计模式官方源码

    15. 状态模式(State Pattern):状态模式允许对象在内部状态改变时改变其行为,看起来好像对象改变了它的类。 16. 命令模式(Command Pattern):命令模式将请求封装为一个对象,以便使用不同的请求、队列请求、...

    Design Pattern英文版

    - 状态模式(State):允许对象在其内部状态改变时改变其行为,看起来像是改变了它的类。 - 策略模式(Strategy):定义一系列算法,并将每个算法封装起来,使它们可以相互替换。 - 模板方法模式(Template ...

Global site tag (gtag.js) - Google Analytics