网站开发命名规范,汉中网站制作,金融网站建设方案书,山东省住房和建设厅网站状态模式
策略模式和状态模式是双胞胎#xff0c;在出生时才分开。你已经知道#xff0c;策略模式是围绕可以互换的算法来创建成功业务的#xff0c;然而#xff0c;状态走的是更崇高的路#xff0c;它通过改变对象内部的状态来帮助对象控制自己的行为。
定义状态模式
…状态模式
策略模式和状态模式是双胞胎在出生时才分开。你已经知道策略模式是围绕可以互换的算法来创建成功业务的然而状态走的是更崇高的路它通过改变对象内部的状态来帮助对象控制自己的行为。
定义状态模式
先看看定义状态模式允许对象在内部状态改变时改变它的行为对象看起来好像修改了它的类
例题
自动糖果售卖机糖果机的控制器需要的工作流程如下图 从上面的状态图中可以找到所有的状态 我们可以创建一个实例变量来持有目前的状态然后定义每个状态的值 1 2 3 4 5 6 7 //每个状态用不同的值表示 final static int SOLD_OUT0;//售罄 final static int NO_QUARTER1;//没有投币 final static int HAS_QUARTER2;//已投币 final static int SOLD3;//售出糖果 //实例变量持有当前状态只要改变变量值状态也会随之改变 int state SOLD_OUT;
现在,我们将所有系统中可以发生的动作整合起来 “投入25分钱”“退回25分钱”“转动曲柄”“发放糖果” 这些动作是糖果机的接口这是你能对糖果机做的事情 调用任何一个动作都会造成状态的转换 发放糖果更多是糖果机的内部动作机器自己调用自己。
我们创建一个类它的作用就像是一个状态机每一个动作我们都创建了一个对应的方法这些方法利用条件语句来决定在每个状态内什么行为是恰当的。比如对“投入25分钱”这个动作来说我们可以把对应方法写成下面的样子 1 2 3 4 5 6 7 8 9 10 11 12 13 public void insertQuarter(){ if(stateHAS_QUARTER){ //每个状态对应的行为 ...... }else if(stateSOLD_OUT){ ...... }else if(state SOLD){ ...... }else if(stateNO_QUARTER){ stateHAS_QUARTER;//状态转换 ...... } }
初步代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 class GumballMachine{ final static int SOLD_OUT0; final static int NO_QUARTER1; final static int HAS_QUARTER2; final static int SOLD3; int state SOLD_OUT; int count 0;//存储糖果数量 public GumballMachine(int count){ this.countcount; if(count0){ stateNO_QUARTER; } } //当有25分钱投入就会执行这个方法 public void insertQuarter(){ if(stateHAS_QUARTER){ System.out.println(如果已投入过25分钱我们就告诉顾客); }else if(stateNO_QUARTER){ stateHAS_QUARTER; System.out.println(如果是在“没有25分钱”的状态下我们就接收25分钱 并将状态转换到“有25分钱”的状态); }else if(state SOLD_OUT){ System.out.println(如果糖果已经售罄我们就拒绝收钱); }else if(stateSOLD){ System.out.println(如果顾客刚才买了糖果就需要稍等一下好让状态转换完毕。 恢复到“没有25分钱”的状态); stateNO_QUARTER; } } //如果顾客试着退回25分钱就执行这个方法 public void ejectQuarter(){ if(stateHAS_QUARTER){ System.out.println(如果有25分钱我们就把钱退出来回到“没有25分钱”的状态); stateNO_QUARTER; }else if(stateNO_QUARTER){ System.out.println(如果没有25分钱的话当然不能退出25分钱); }else if(state SOLD){ System.out.println(顾客已经转动曲柄就不能再退钱了他已经拿到糖果了); }else if(stateSOLD_OUT){ System.out.println(如果糖果售罄就不能接受25分钱当然也不可能退钱); } } //顾客试着转动曲柄 public void turnCrank(){ if(stateSOLD){ System.out.println(别想骗过机器拿两次糖果); }else if(stateNO_QUARTER){ System.out.println(我们需要先投入25分钱); }else if(state SOLD_OUT){ System.out.println(我们不能给糖果已经没有任何糖果了); }else if(stateHAS_QUARTER){ System.out.println(成功他们拿到糖果了 改变状态到“售出糖果”然后调用机器的disoense()方法); stateSOLD; dispense(); } } //调用此方法发放糖果 public void dispense(){ if(stateSOLD){ System.out.println(我们正在“出售糖果”状态给他们糖果); countcount-1; /* 我们在这里处理“糖果售罄”的情况如果这是最后一个糖果将机器的状态设置到“糖果售罄”否则就回到“没有25分钱”的状态 */ if(count0){ System.out.println(); stateSOLD_OUT; }else{ stateNO_QUARTER; } }else if(stateSOLD_OUT){ System.out.println(这些都不应该发生但是如果做了就得到错误提示); }else if(state HAS_QUARTER){ System.out.println(这些都不应该发生但是如果做了就得到错误提示); }else if(stateNO_QUARTER){ System.out.println(这些都不应该发生但是如果做了就得到错误提示); } } }
尽管程序完美运行但还是躲不掉需求变更的命运
现在糖果公司要求当曲柄被转动时有10%的几率掉下来的是两个糖果。氪金扭蛋
再回看一下我们的初步代码想要实现新的需求将会变得非常麻烦
必须新增一个中奖的“赢家”状态。必须在每一个方法添加新的判断条件来处理“赢家”状态。转动把手的方法中还需要检查目前状态是否是“赢家”再决定切换到“赢家”状态行为还是正常出售行为。
在现有代码基础上做增加将会很麻烦也不利与以后的维护扩展性差。
回顾一下第一章的策略模式中的设计原则 找出应用中可能需要变化之处把他们独立出来 将状态独立出来封装成一个类都实现State接口类图如下 新的设计想法如下
首先我们定义一个State接口在这个接口内糖果机的每个动作都有一个对应的方法然后为机器的每个状态实现状态类这些类将负责在对应的状态下进行机器的行为最后我们要摆脱旧的条件代码取而代之的方式是将动作委托到状态类
代码
定义一个State接口 1 2 3 4 5 6 public interface State { public void insertQuarter();//投币 public void ejectQuarter();//退币 public void turnCrank();//转动出货把手 public void dispense();//出售 }
为机器的每个状态实现状态类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 //未投币状态 public class NoQuarterState implements State { GumballMachine gumballMachine; public NoQuarterState(GumballMachine gumballMachine) { this.gumballMachinegumballMachine; } public void insertQuarter() { System.out.println(你投入一枚硬币); gumballMachine.setState(gumballMachine.getHasQuarterState());//状态转换为已投币状态 } public void ejectQuarter() { System.out.println(你未投币无法退钱); } public void turnCrank() { System.out.println(未投币请先投币); } public void dispense() { System.out.println(请先投币); } } //已投币状态 public class HasQuarterState implements State { Random randomWinnernew Random(System.currentTimeMillis()); GumballMachine gumballMachine; public HasQuarterState(GumballMachine gumballMachine) { this.gumballMachinegumballMachine; } public void insertQuarter() { System.out.println(已投币无法再接收投币); } public void ejectQuarter() { System.out.println(已退币); gumballMachine.setState(gumballMachine.getNoQuarterState()); } public void turnCrank() { System.out.println(已转动把手糖果出售中。。。。); int winnerrandomWinner.nextInt(10);//随机数生成用以标记“赢家”状态 if((winner0)(gumballMachine.getCount()1)) gumballMachine.setState(gumballMachine.getWinnerState()); else gumballMachine.setState(gumballMachine.getSoldState()); } public void dispense() { System.out.println(机器中已经没有糖果可以出售了); } } //出售状态 public class SoldState implements State { GumballMachine gumballMachine; public SoldState(GumballMachine gumballMachine) { this.gumballMachinegumballMachine; } public void insertQuarter() { System.out.println(请等候正在初始化机器中); } public void ejectQuarter() { System.out.println(抱歉您已转动把手获得了糖果,无法退币); } public void turnCrank() { System.out.println(您重复转动把手无法再获取更多糖果); } public void dispense() { gumballMachine.releaseBall();//出货糖果-1 if(gumballMachine.getCount()0) gumballMachine.setState(gumballMachine.getNoQuarterState()); else { System.out.println(糖果已售完); gumballMachine.setState(gumballMachine.getSoldOutState()); } } } //售罄状态 public class SoldOutState implements State { GumballMachine gumballMachine; public SoldOutState(GumballMachine gumballMachine) { this.gumballMachinegumballMachine; } public void insertQuarter() { System.out.println(此机器的糖果已售完不接收投币); } public void ejectQuarter() { System.out.println(未投币退币失败); } public void turnCrank() { System.out.println(糖果已售完转动把手也不会有糖果出来的); } public void dispense() { System.out.println(机器中已无糖果); } } //赢家状态 public class WinnerState implements State { GumballMachine gumballMachine; public WinnerState(GumballMachine gumballMachine) { this.gumballMachinegumballMachine; } public void insertQuarter() { System.out.println(请等候正在初始化机器中); } public void ejectQuarter() { System.out.println(抱歉您已转动把手获得了糖果); } public void turnCrank() { System.out.println(您重复转动把手无法再获取更多糖果); } public void dispense() { System.out.println(恭喜你成为幸运儿你将额外获得一个免费糖果); gumballMachine.releaseBall();//出货糖果-1 if(gumballMachine.getCount()0) gumballMachine.setState(gumballMachine.getSoldOutState()); else { gumballMachine.releaseBall(); if(gumballMachine.getCount()0) gumballMachine.setState(gumballMachine.getNoQuarterState()); else { System.out.println(糖果已售完); gumballMachine.setState(gumballMachine.getSoldOutState()); } } } }
糖果机类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 public class GumballMachine { State soldOutState; State noQuarterState; State hasQuarterState; State soldState; State winnerState; State statesoldOutState; int count0; public GumballMachine(int numberGumballs) {//初始化 soldOutStatenew SoldOutState(this); noQuarterStatenew NoQuarterState(this); hasQuarterStatenew HasQuarterState(this); soldStatenew SoldState(this); winnerStatenew WinnerState(this); this.countnumberGumballs; if(numberGumballs0) statenoQuarterState;//先判断条件再改变状态 } //将动作委托到状态类 public void insterQuarter() { state.insertQuarter(); } public void ejectQuarter() { state.ejectQuarter(); } public void turnCrank() { state.turnCrank(); state.dispense(); } //获取当前状态 public State getHasQuarterState() { return hasQuarterState; } //改变状态 public void setState(State state) { this.statestate; } public void releaseBall() { System.out.println(糖果从出口售出); if(count!0) count-1; } public State getSoldOutState() { return soldOutState; } public State getNoQuarterState() { return noQuarterState; } public State getSoldState() { return soldState; } //获取糖果机中糖果数量 public int getCount() { return count; } public State getWinnerState() { return winnerState; } public String toString() { // TODO 自动生成的方法存根 String s剩余糖果count; return s; } }
以上就是用状态模式实现的仔细观察你会发现状态模式其实和策略模式很像来看看状态模式的类图 状态模式的类图其实和策略模式完全一样
状态模式与策略模式
这两个模式的差别在于它们的“意图”
以状态模式而言我们将一群行为封装在状态对象中context的行为随时可委托到那些状态对象中的一个随着时间而流逝当前状态在状态对象集合中游走改变以反映出context内部的状态因此context的行为也会跟着改变但是context的客户对于状态对象了解不多甚至根本是浑然不觉。以策略模式而言客户通常主动指定Context所要组合的策略对象时哪一个。现在固然策略模式让我们具有弹性能够在运行时改变策略但对于某个context对象来说通常都只有一个最适当的策略对象。一般的我们把策略模式想成是除了继承之外的一种弹性替代方案如果你使用继承定义了一个类的行为你将被这个行为困住是指要修改它都很难有了策略模式你可以通过组合不同的对象来改变行为。我们把状态模式想成是不用在context中放置许多条件判断的替代方案通过将行为包装进状态对象中你可以通过在context内简单地改变状态对象来改变context的行为。
模式区分
状态模式封装基于状态的行为并将行为委托到当前状态
策略模式将可以互换的行为封装起来。然后使用委托的方法觉得使用哪一个行为
模板方法模式由子类决定如何实现算法中的某些步骤
要点
1状态模式允许一个对象基于内部状态而拥有不同的行为。
2和程序状态机PSM不同状态模式用类来表示状态。
3Context会将行为委托给当前状态对象。
4通过将每一个状态封装进一个类我们把以后需要做的任何改变局部化了。
5状态模式和策略模式有相同的类图但是他们的意图不同。
6策略模式通常会用行为或算法配置Context类。
7状态模式允许Context随着状态的改变而改变行为。
8状态转换可以有State类或Context类控制。
9使用状态模式通常会导致设计中类的数目大量增加。
10状态栏可以被多个Context实例共享。