java设计模式之State(状态)

来源:互联网 发布:暴走大事件 恶劣 知乎 编辑:程序博客网 时间:2024/06/05 12:39

状态模式是在程序开发时,经常用到的模式。如果没有应用过,而实现业务功能。那你也一定是按照状态模式的路子走的,只不过你没有感觉到而已。它的实现,是要根据对象的内部状态变化,而自动执行相应的功能。

    费话就不说了,请看一下源代码,这也是我研究设计模式时看到的一个例子,把其翻译成中文,使个位网友能够看懂些,由于水平有限,只能达到这样,还希望读者多指证,谢谢啊。

1.         public class GumballMachine {

2.               //这就是那4个状态,每个状态都用一个不同的整数代表,他们符合状态图

3.             final static int SOLD_OUT = 0; //糖果售完状态

4.             final static int NO_QUARTER = 1; //没有钱状态

5.             final static int HAS_QUARTER = 2; //有钱状态

6.             final static int SOLD = 3; //售出糖果

7.              //这个实例变量跟踪当前状态,一开始被设为"糖果售完",因为糖果机安装时是没有装糖果的

8.             int state = SOLD_OUT;

9.             int count = 0; //这个变量用来追踪机器内的糖果数目

10.          //构造器初始糖果库存量当做参数,如果库存不为0的话,机器就进入"没有钱"的状态,等着你向里投钱

11.         public GumballMachine(int count) {

12.             this.count = count;

13.             if (count > 0) {

14.                 state = NO_QUARTER;

15.             }

16.         }

17.      

18.          //当把钱投入进来,就会执行这里

19.         public void insertQuarter() {

20.             if (state == HAS_QUARTER) {

21.              //如果此时的状态为有钱状态,则通知顾客

22.                 System.out.println("你不能再向糖果机里投钱了");

23.             } else if (state == NO_QUARTER) {

24.                 //如果是在"没有25分钱"的状态下,我们就接受25分钱,并将状态转换到"25分钱"

25.                 state = HAS_QUARTER;

26.                 System.out.println("你可以向糖果机里投钱");

27.             } else if (state == SOLD_OUT) {

28.                 //如果糖果售完,就拒绝收钱

29.                 System.out.println("糖果已经卖完,不能再向里投钱了");

30.             } else if (state == SOLD) {

31.                 //如果顾客买到糖果,就需要稍等下,好让状态转换完毕,恢复到"没有25分钱"的状态

32.                 System.out.println("已向你卖出一个糖果,请稍等,再向里投钱。");

33.             }

34.         }

35.         //现在,如果顾客试着退回25分钱...

36.         public void ejectQuarter() {

37.             if (state == HAS_QUARTER) {

38.                 //如果有25分钱,就退钱,回到"没有25分钱"的状态

39.                 System.out.println("退钱成功");

40.                 state = NO_QUARTER;

41.             } else if (state == NO_QUARTER) {

42.                 //如果没有25分钱,当然不能退回

43.                 System.out.println("没有钱,你不能退钱");

44.             } else if (state == SOLD) {

45.                 //如果顾客已经转动手柄,就不能退钱了,他已经拿到糖果了

46.                   state = NO_QUARTER;

47.                 System.out.println("对不起,糖果已经卖出不能退钱。");

48.             } else if (state == SOLD_OUT) {

49.                 //如果糖果售完,就不可能接受25分钱,当然也不可能退钱

50.                 System.out.println("对不起,糖果已经卖完不能退钱");

51.             }

52.         }

53.          //顾客试着转动手柄...

54.         public void turnCrank() {

55.             if (state == SOLD) {

56.                 //别想骗过机器拿2次糖果

57.                 System.out.println("不能再给你了");

58.             } else if (state == NO_QUARTER) {

59.                 //我们需要先投入25分钱

60.                 System.out.println("你没有投钱糖果不能卖给你");

61.             } else if (state == SOLD_OUT) {

62.                 //没有糖果了

63.                 System.out.println("糖果机中没有糖果了,你不能进行交易。");

64.             } else if (state == HAS_QUARTER) {

65.                 //成功!他拿到糖果了.改变状态到"售出糖果",然后调用机器的dispense()方法

66.                 System.out.println("请稍等,一会糖果你就可以拿到了...");

67.                 state = SOLD;

68.                 dispense();

69.             }

70.         }

71.          //发放糖果

72.         public void dispense() {

73.             if (state == SOLD) {

74.                 //我们正在"售出糖果"状态

75.                 System.out.println("一个糖果将从这里出来....");

76.                 count = count - 1;

77.                 //我们在这里处理"糖果售完"的情况

78.                 if (count == 0) {  //最后一颗,将机器设置到"糖果售完"状态

79.                     System.out.println("库存为零!");

80.                     state = SOLD_OUT;

81.                 } else { //否则回到"没有25分钱"的状态

82.                     state = NO_QUARTER;

83.                 }

84.             } else if (state == NO_QUARTER) {

85.                 //以下都不应该发生,但如果顾客这么做了,得到的应该是错误消息而不是糖果

86.                 System.out.println("你需要向糖果机里投钱。。");

87.             } else if (state == SOLD_OUT) {

88.                 System.out.println("糖果已经卖没了");

89.             } else if (state == HAS_QUARTER) {

90.                 System.out.println("请您稍等交易还没有结束。");

91.             }

92.         }

93.     }

测试就来自已写吧,我提供个思路,就是页面提供几个开关,即按纽、checkbox等在它们的单击事件上GumballMachine实例的内部状态改变。然后看其变化,就可以了。

大家看没看出来,这段代码还有一些怪的味道呀,这时如果业务变化了,如果客户是一个中奖的用户,需要糖果机吐出两块糖果,怎么办?,是不是还得在各个方法中把这个状态给加上呀,又得加一个if语句呢,这是一个业务发生了变化,如果业务要无限的变化下去,程序员是不是都要疯了,哈哈。所以要对其进行重构了。

要把这几个状态抽象出来。想到这里看一下代码就明白了。

Java代码

1.         public interface State {

2.             //投钱的状态

3.             public void insertQuarter();

4.             //退钱的状态

5.             public void ejectQuarter();

6.             //按下按纽状态

7.             public void turnCrank();

8.             //发放物品状态

9.             public void dispense();  

10.     }

 

下面是几个实现这个状态接口的实现类。 

Java代码 

1.         public class HasQuarterState implements State {

2.             GumballMachineTwo gumballMachine;

3.             //增加一个随机数产生器,产生10%的机会

4.             Random randomWinner = new Random(System.currentTimeMillis());

5.             public HasQuarterState(GumballMachineTwo gumballMachine) {

6.                 this.gumballMachine = gumballMachine;

7.             }

8.             public void insertQuarter() { //这是一个对当前状态不恰当的动作

9.                 System.out.println("不能再投钱了,已经有钱了。");

10.         }

11.      

12.         public void ejectQuarter() { //退钱并转换状态到NoQuarterState

13.             System.out.println("退钱返回");

14.             //把糖果机从有钱状态改成没钱状态

15.             gumballMachine.setState(gumballMachine.getNoQuarterState());

16.         }

17.      

18.         public void turnCrank() {

19.             System.out.println("请稍等,一会糖果你就可以拿到了...");

20.             int winner = randomWinner.nextInt(10);

21.             //决定这个顾客是否赢了

22.             if ((winner == 0) && (gumballMachine.getCount() > 1)) {

23.                 gumballMachine.setState(gumballMachine.getWinnerState());

24.             } else {

25.                 gumballMachine.setState(gumballMachine.getSoldState());

26.             }

27.         }

28.         public void dispense() { //这是一个对当前状态不恰当的动作

29.             System.out.println("请您稍等交易还没有结束。");

30.         }

31.     }

32.      

33.     public class NoQuarterState implements State {

34.         GumballMachineTwo gumballMachine;

35.      

36.         // 通过构造器得到糖果机的引用

37.         public NoQuarterState(GumballMachineTwo gumballMachine) {

38.             this.gumballMachine = gumballMachine;

39.         }

40.      

41.         // 分发物品

42.         public void dispense() {

43.             System.out.println("没有钱,不能分发糖果");

44.         }

45.      

46.         // 退钱

47.         public void ejectQuarter() {

48.             System.out.println("没有钱,不能退钱");

49.         }

50.      

51.         // 投钱

52.         public void insertQuarter() {

53.             // TODO Auto-generated method stub

54.         }

55.      

56.         // 按纽操作

57.         public void turnCrank() {

58.             // TODO Auto-generated method stub

59.         }

60.     }

61.      

62.     public class SoldOutState implements State {

63.         GumballMachineTwo gumballMachine;

64.      

65.         public SoldOutState(GumballMachineTwo gumballMachine) {

66.             this.gumballMachine = gumballMachine;

67.         }

68.      

69.         public void dispense() {

70.             System.out.println("糖果已经卖没了");

71.         }

72.      

73.         public void ejectQuarter() {

74.             System.out.println("对不起,糖果已经卖完不能退钱");

75.      

76.         }

77.      

78.         public void insertQuarter() {

79.             System.out.println("糖果已经卖完,不能再向里投钱了");

80.         }

81.      

82.         public void turnCrank() {

83.             // TODO Auto-generated method stub

84.         }

85.     }

86.      

87.     public class SoldState implements State {

88.         GumballMachineTwo gumballMachine;

89.         public SoldState(GumballMachineTwo gumballMachine) {

90.             this.gumballMachine = gumballMachine;

91.         }

92.         //以下3个方法对此状态来说都是不恰当的

93.         public void insertQuarter() {

94.             System.out.println("已向你卖出一个糖果,请稍等,再向里投钱。");

95.         }

96.         public void ejectQuarter() {

97.             System.out.println("对不起,糖果已经卖出不能退钱");

98.         }

99.         public void turnCrank() {

100.        System.out.println("糖果已经卖出,不能再给你了");

101.    }

102.    //首先让机器发放糖果

103.    public void dispense() {

104.        gumballMachine.releaseBall();

105.        if (gumballMachine.getCount() > 0) {

106.            gumballMachine.setState(gumballMachine.getNoQuarterState());

107.        } else {

108.            System.out.println("Oops, out of gumballs!");

109.            gumballMachine.setState(gumballMachine.getSoldOutState());

110.        }

111.    }

112.}

113. 

114. public class WinnerState implements State {

115.    GumballMachineTwo gumballMachine;

116.    //下面都跟SoldState方法一样

117.    public WinnerState(GumballMachineTwo gumballMachine) {

118.        this.gumballMachine = gumballMachine;

119.    }

120.    public void insertQuarter() {

121.        System.out.println("Please wait, we're already giving you a Gumball");

122.    }

123.    public void ejectQuarter() {

124.        System.out.println("Please wait, we're already giving you a Gumball");

125.    }

126.    public void turnCrank() {

127.        System.out.println("Turning again doesn't get you another gumball!");

128.    }

129.    //我们在这里发放出2颗糖果,然后进入NoQuarterStateSoldState

130.    public void dispense() {

131.        System.out.println("YOU'RE A WINNER! You get two gumballs for your quarter");

132.        gumballMachine.releaseBall();

133.        if (gumballMachine.getCount() == 0) {

134.            gumballMachine.setState(gumballMachine.getSoldOutState());

135.        } else {

136.            gumballMachine.releaseBall();

137.            if (gumballMachine.getCount() > 0) {

138.                gumballMachine.setState(gumballMachine.getNoQuarterState());

139.            } else {

140.                System.out.println("Oops, out of gumballs!");

141.                gumballMachine.setState(gumballMachine.getSoldOutState());

142.            }

143.        }

144.    }

145.}

下面是新的糖果类:

Java代码 

1.         public class GumballMachineTwo {

2.             //所有的状态都在这里

3.             State soldOutState;

4.             State noQuarterState;

5.             State hasQuarterState;

6.             State soldState;

7.          

8.             State winnerState;//十次抽中一次的游戏,新的状态

9.             //以及实例变量state

10.         State state = soldOutState;

11.         int count = 0;//记录糖果数量

12.         public GumballMachineTwo(int numberGumballs) {

13.             soldOutState = new SoldOutState(this); //每一种状态也都创建一个状态实例

14.             noQuarterState = new NoQuarterState(this);

15.             hasQuarterState = new HasQuarterState(this);

16.             soldState = new SoldState(this);

17.             this.count = numberGumballs;

18.             if (numberGumballs > 0) { //如果超过0颗糖果,状态设为noQuarterState

19.                 state = noQuarterState;

20.             }

21.         }

22.         //委托给当前状态

23.         public void insertQuarter() {

24.             state.insertQuarter();

25.         }

26.         public void ejectQuarter() {

27.             state.ejectQuarter();

28.         }

29.         //dispense()是一个内部动作方法,用户不可以直接要求机器发放糖果

30.         public void turnCrank() {

31.             state.turnCrank();

32.             state.dispense();

33.         }

34.         //允许其他的对象将机器状态转换到不同的状态

35.         void setState(State state) {

36.             this.state = state;

37.         }

38.         //辅助方法释放出糖果,并将count实例变量值减1

39.         void releaseBall() {

40.             System.out.println("A gumball comes rolling out the slot...");

41.             if (count != 0) {

42.                 count = count - 1;

43.             }

44.         }

45.         int getCount() {

46.             return count;

47.         }

48.         void refill(int count) {

49.             this.count = count;

50.             state = noQuarterState;

51.         }

52.         public State getState() {return state;}

53.         public State getSoldOutState() {return soldOutState;}

54.         public State getNoQuarterState() {return noQuarterState;}

55.         public State getHasQuarterState() {return hasQuarterState;}

56.         public State getSoldState() {return soldState;}

57.         public State getWinnerState() {return winnerState;}

58.     }