状态模式(State Design Pattern)
来源:互联网 发布:c语言产生随机数的方法 编辑:程序博客网 时间:2024/06/08 06:34
以此回顾《设计模式之禅》及其他设计模式书籍、视频中的状态模式。
什么是状态模式?
Allow an object to alter its behavior when its internal state changes. The object will appear to change its class. (当一个对象的内在状态改变时,允许它修改自己的行为。这个对象看起来像是改变了类)
状态模式有3个重要部分。(1)Context(Account)(2)State (3)Concrete State
如何理解状态模式中的Context?
Context(Account):Maintains an instance of a ConcreteState subclass that defines current state。持有一个定义了当前状态的实例,这个“当前状态”就是一个具体状态(ConcreteState),实现了State,是State的子集。
如何理解状态模式中的State?
State:Defines an interface for encapsulating the behavior associated with a particular state of the context. 定义了一个接口,接口里包含了context持有的具体状态要实现的方法。
如何理解状态模式中的Concrete State?
Concrete State:Each subclass implements a behavior associated with a state of context。具体状态里实现了接口中定义的方法。
理解了这3个部分,再看定义,不难发现,状态模式其实就是说,当context持有的某个状态(concrete state)改变时,它的行为也发生了改变(因为每个concrete state对state接口中定义的方法的实现不同,行为也就不同)。
例如,把电梯抽象出4个状态,分别是运行、停止、开门、关门,则它的状态模式UML类图为:
使用状态模式的好处?
(1)结构清晰。
避免了switch...case或者if...else的使用,减少了程序的负责行,使逻辑清晰。试想,刚才的电梯的例子,假设不用状态模式,则会变成这样,直接上代码:
public void close() { //电梯在什么情况下能关闭 switch(state) { //如果此时门开着 case OPEN_DOOR_STATE: //可以关门 this.closeDoor(); this.setState(CLOSE_DOOR_STATE); break; //如果此时门关着 case CLOSE_DOOR_STATE: //do nothing break; //如果此时电梯正在运行 case RUN_STATE: //do nothing break; //如果此时电梯停止运行 case STOP_STATE: //do nothing break; }}//同理,开门public void openDoor() { //电梯什么情况下能开门 switch(state) { case XXX:break; case XXX:break; case XXX:break; case XXX:break; }}//同理,运行public void run() { //电梯什么情况下能运行 switch(state) { case XXX:break; case XXX:break; case XXX:break; case XXX:break; }}//同理,停止public void stop() { //电梯什么情况下能停止 switch(state) { case XXX:break; case XXX:break; case XXX:break; case XXX:break; }}显然,大量的switch case语句这个类过长,程序逻辑结构复杂,不容易理解,难以维护。
(2)遵循设计原则
状态模式很好的体现了开闭原则和单一职责原则,每个状态都是一个子类,只要增加子类,就能进行扩展,比如电梯的例子,如果想增加通电和断电状态,直接增加子类就可以实现,但是如果用上面的未使用状态模式的代码,就会又增加一大波判断,逻辑更加复杂,且破坏了开闭原则。
(3)封装性好
这也是状态模式的要求,将类的变换放置到类的内部来实现,外部的调用不知道类内部如何实现状态和行为的变换,符合迪米特法则(最少知道法则)。
如何使用状态模式?
用ATM机的例子(来自于视频:https://www.youtube.com/watch?v=MGEx35FjBuo)来讲一个状态模式的应用。1、想想ATM机的所有可能状态。
(1)HasCard
(2)NoCard
(3)HasPin
(4)NoCash
2、想想人们使用ATM机的几种操作。
(1)InsertCard
(2)EjectCard
(3)InsertPin
(4)RequestCash
3、UML类图
4、具体代码
ATMState.java
public interface ATMState { void insertCard(); void ejectCard(); void insertPin(int pinEntered); void requestCash(int cashToWithdraw);}ATMMachine.java
public class ATMMachine { ATMState hasCard; ATMState noCard; ATMState hasCorrectPin; ATMState atmOutOfMoney; ATMState atmState; int cashInMachine = 2000; boolean correctPinEntered = false; public ATMMachine() { hasCard = new HasCard(this); noCard = new NoCard(this); hasCorrectPin = new HasPin(this); atmOutOfMoney = new NoCash(this); atmState = noCard; if (cashInMachine < 0) { atmState = atmOutOfMoney; } } void setAtmState(ATMState newAtmState) { atmState = newAtmState; } public void setCashInMachine(int newCashInMachine) { cashInMachine = newCashInMachine; } public void insertCard() { atmState.insertCard(); } public void ejectCard() { atmState.ejectCard(); } public void requestCash(int cashToWithdraw) { atmState.requestCash(cashToWithdraw); } public void insertPin(int pinEntered) { atmState.insertPin(pinEntered); } public ATMState getYesCardState() { return hasCard; } public ATMState getNoCardState() { return noCard; } public ATMState getHasCorrectPinState() { return hasCorrectPin; } public ATMState getAtmOutOfMoneyState() { return atmOutOfMoney; }}
HasCard.java
public class HasCard implements ATMState { ATMMachine atmMachine; public HasCard(ATMMachine atmMachine) { this.atmMachine = atmMachine; } @Override public void insertCard() { System.out.println("You can't enter more than one card!"); } @Override public void ejectCard() { System.out.print("Card ejected"); atmMachine.setAtmState(atmMachine.getNoCardState()); } @Override public void insertPin(int pinEntered) { if (pinEntered == 1234) { System.out.println("Correct Pin"); atmMachine.correctPinEntered = true; atmMachine.setAtmState(atmMachine.getHasCorrectPinState()); } else { System.out.println("Wrong Pin"); atmMachine.correctPinEntered = false; System.out.println("Card ejected"); atmMachine.setAtmState(atmMachine.getNoCardState()); } } @Override public void requestCash(int cashToWithdraw) { System.out.println("Enter pin first"); }}
NoCard.java
public class NoCard implements ATMState { ATMMachine atmMachine; public NoCard(ATMMachine atmMachine) { this.atmMachine = atmMachine; } @Override public void insertCard() { System.out.println("Please enter a pin"); atmMachine.setAtmState(atmMachine.getYesCardState()); } @Override public void ejectCard() { System.out.println("Enter a card first"); } @Override public void insertPin(int pinEntered) { System.out.println("Enter a card first"); } @Override public void requestCash(int cashToWithdraw) { System.out.println("Enter a card first"); }}
HasPin.java
public class HasPin implements ATMState { ATMMachine atmMachine; public HasPin(ATMMachine atmMachine) { this.atmMachine = atmMachine; } @Override public void insertCard() { System.out.println("You can't enter more than one card"); } @Override public void ejectCard() { System.out.println("Card ejected"); atmMachine.setAtmState(atmMachine.getNoCardState()); } @Override public void insertPin(int pinEntered) { System.out.println("Already entered pin"); } @Override public void requestCash(int cashToWithdraw) { if (cashToWithdraw > atmMachine.cashInMachine) { System.out.println("Don't have that cash"); System.out.println("Card ejected"); atmMachine.setAtmState(atmMachine.getNoCardState()); } else { System.out.println(cashToWithdraw + " is provided by machine"); atmMachine.setCashInMachine(atmMachine.cashInMachine - cashToWithdraw); System.out.println("Card ejected"); atmMachine.setAtmState(atmMachine.getNoCardState()); if (atmMachine.cashInMachine <= 0) { atmMachine.setAtmState(atmMachine.getAtmOutOfMoneyState()); } } }}
NoCash.java
public class NoCash implements ATMState { ATMMachine atmMachine; public NoCash(ATMMachine atmMachine) { this.atmMachine = atmMachine; } @Override public void insertCard() { System.out.println("We don't have money"); } @Override public void ejectCard() { System.out.println("We don't have money, you didn't enter a card"); } @Override public void insertPin(int pinEntered) { System.out.println("We don't have money"); } @Override public void requestCash(int cashToWithdraw) { System.out.println("We don't have money"); }}
TestATMMachine.java
public class TestATMMachine { public static void main(String[] args) { ATMMachine atmMachine = new ATMMachine(); atmMachine.insertCard(); atmMachine.ejectCard(); atmMachine.insertCard(); atmMachine.insertPin(1234); atmMachine.requestCash(2000); atmMachine.requestCash(100); atmMachine.insertCard(); atmMachine.insertPin(1234); }}
什么时候使用状态模式,以及状态模式的注意事项?
(1)状态模式适用于某个对象当他的状态改变时,行为也有有较大变化的时候,考虑使用状态模式,但是对象的状态最好不要超过5个,否则会出现类爆炸,不好管理。
(2)当程序中有大量的if else 或者 switch case导致逻辑结构不清晰时,可以考虑状态模式。
- 状态模式(State Design Pattern)
- State Design Pattern 状态设计模式
- State Design Pattern 状态设计模式2
- State Pattern(状态模式)
- State Pattern(状态模式)
- 状态模式(State Pattern)
- 状态模式(State Pattern)
- 状态模式(State Pattern)
- 状态模式(State Pattern)
- 状态模式(State Pattern)
- 状态模式(State Pattern)
- 状态模式(State Pattern)
- 状态模式(State Pattern)
- 状态模式(State Pattern)
- 设计模式学习—状态模式(State Design Pattern)
- 状态模式(State Pattern)
- 状态模式(State Pattern)
- 状态模式(State Pattern)
- 开篇之作
- Axis2开发webservice案例详解
- 练习25:更多练习
- DeepLearning论文笔记(二):Understanding Deep Architectures using a Recursive Convolutional Network
- vim 编辑器配置
- 状态模式(State Design Pattern)
- 取模与取余
- (总结)Nginx配置文件nginx.conf中文详解
- IE浏览器无法上网:该设备或资源(127.0.0.1)未设置为接受端口“16823”上的连接。
- NavigationView解决Item图标不显示原始颜色
- hdu 1789 Doing Homework again(贪心)
- LeetCode-85.Maximal Rectangle
- uva679--Dropping Balls--满二叉树
- 第十一周项目4——教师兼干部类