合工大很牛很牛牛

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  14 Posts :: 1 Stories :: 37 Comments :: 0 Trackbacks
 一个糖果机,有四个状态,状态图如下:

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

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中,新增一个状态,只需要新增一个(表达这个状态的)类,并在该状态的“上游状态”做少许改动即可。

posted on 2008-07-18 00:38 化的了 阅读(2835) 评论(8)  编辑  收藏 所属分类: 设计模式

Feedback

# re: State Pattern 状态模式 2008-07-18 08:45 melland
都是head first design pattern上的例子呀  回复  更多评论
  

# re: State Pattern 状态模式 2008-07-18 09:13 Always BaNg.
我不知道写这种非自己原创,并且资料随处可查的东西有什么意义?

或许你写State Pattern但可以加入自己在实际工程使用过程中的体会啊。

纯碎的抄袭是可耻的,不指明原处的抄袭更加可耻!


没有攻击楼主的意思,是不过对于一个严格要求自己的程序员来说,应该做的更好一些。  回复  更多评论
  

# re: State Pattern 状态模式 2008-07-18 13:40 ron
如果状态变化不频繁,没有必要使用这种方式。代码膨胀,可读性极差!我喜欢使用表驱动。将状态和变换方式存储为表的横格和竖格,将状态处理函数指针存储为表格的内容。如果想扩展,增加行或者列即可。
----------------
老实说,你文中给的那个例子太啰嗦了。  回复  更多评论
  

# re: State Pattern 状态模式 2008-07-18 15:20 化的了
@Always BaNg.
书的确是看的《Head first desgin pattern》
举的例子也的确是书上的。

但代码是自己写的,文字思路是自己的,UML图是自己画的。。。不存在抄袭的问题。只是想自己总结一下这些设计模式的思路的产生过程。

本人还是学生,看书学习为主,项目经验几乎没有,写的不好,希望大家理解。有的东西,其实是写给自己看的,放在网上,大家觉得好,也可以分享。觉得不好,就算了。  回复  更多评论
  

# re: State Pattern 状态模式 2008-07-18 15:52 Always BaNg.
@化的了
不好意思,如果是學生,我說的有些過分,先表示歉意。

不過現在學校一般教的都很爛,你更應該把時間花在比如數學,操作系統,計算機原理,編譯原理,硬件相關的編程上面,設計模式的本意是在有很大量設計之后才產生的模式,即細節已不是什么大問題,全局是問題。如果計算機基礎都不牢固,空談這些模式沒什么意義,先把細節搞清楚才是王道。

再者,多參與一些項目實踐,對自己很有好處。

最后,祝博主學業有成!


  回复  更多评论
  

# re: State Pattern 状态模式 2008-07-22 14:13 Bruce Luo
switch(month){
case 1,3,5,7,8,10,12:
day=31;break;
case 4,6,9,11:
day=30;break;
case 2:
day=28;break;
}
使用表驱动法:
var days=new Array(31,28,31,30,31,30,31,31,30,31,30,31);
day=days[month-1];
  回复  更多评论
  

# re: State Pattern 状态模式[未登录] 2008-12-03 14:46 aa
这样的烂东西不要放上来,浪费大家的时间  回复  更多评论
  

# re: State Pattern 状态模式 2009-03-17 16:13 zdcin
@ron
我深有同感,表驱动的状态模式比这种代码简洁多了(只有架构代码,数据全在表中),而且更能抽象状态的变化流转,更具有通用性,类实现的状态机,架构代码也应用代码混淆,而且应用代码重复(状态有多少个就重复多少次),在应用代码中可以任意跳转,看代码都能把人看晕,实在不知道GOF讲设计模式时为什么不多讲讲类方式状态机的弊端,以至造成类方式状态机的泛滥。  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航: