一、什么是状态模式
定义:允许对象在内部状态改变时改变它的行为,对象看起来好像改变了它的类
二、什么时候用状态模式?
当控制一个对象状态转换的条件表达式过于复杂时,使用状态模式。把状态的判断逻辑转移到表示不同的一系列类当中,可以把复杂的逻辑判断简单化。(避免了写很多的if。。。。else)
三、状态模式构成
Context上下文:定义一个客户端需要的接口,维护一个具体状态角色的实例并将所有动作交由当前状态对象处理。
State:一个接口,用于定义与Context行为相关的特定状态
ConcreteState:具体的某个状态
四、举个例子
一家公司发明了一款糖果机,需要你设计一个程序来控制糖果机的运行。初始状态下:糖果机中没有任何糖果,当有人投入硬币后,可以选择按钮以此来获得糖果,或者选择退钱按钮以此来退出钱。如果当前选择了获取糖果,糖果机中吐出一个糖果,当糖果机中的糖果数量为0时候,糖果机进入停运状态。
分析:这其中涉及糖果机状态的转换:
起初:糖果机为未支付状态(noPayment)—(支付硬币)—>已支付状态—(按吐糖果按钮)—>售出糖果—[(如果糖果数量为0)—>停运状态,],[(如果不为0)->未支付状态]
也可以是:未支付状态(noPayment)—(支付硬币)—>已支付状态—(退钱)—>未支付状态
这里面涉及四个状态:未支付状态,以支付状态,出售糖果状态,停运状态
动作:投币,按吐糖果按钮,退钱,发放糖果
class SugerMachine{
private int count;
private State noPaymentState;
private State paymentState;
private State soldState;
private State outAgeState;
private State currentState;
public SugerMachine(int count){
this.count=count;
noPaymentState=new NoPaymentState(this);
paymentState=new PaymentState(this);
soldState=new SoldState(this);
outAgeState=new PaymentState(this);
this.currentState=noPaymentState;
}
public void payMent(){
this.currentState.payMent();
}
public void ejectMeney(){
this.currentState.ejectMoney();
}
public void trunMoney(){
this.currentState.turnButton();
this.currentState.grantSuger();//这是一个内部动作,不需要外部用户访问
}
public void setState(State state){
this.currentState=state;
}
public State getNoPaymentState() {
return noPaymentState;
}
public State getOutAgeState() {
return outAgeState;
}
public State getSoldState() {
return soldState;
}
public State getPaymentState() {
return paymentState;
}
public int getCount() {
return count;
}
public void removeSuger(){
this.count-=1;
}
}
/**
* 抽象状态
*/
interface State{
public void payMent();
public void ejectMoney();
public void turnButton();
public void grantSuger();
}
/**
* 以下为具体的四个状态
*/
class NoPaymentState implements State{
private SugerMachine sugerMachine;
public NoPaymentState(SugerMachine SugerMachine) {
this.sugerMachine = SugerMachine;
}
@Override
public void payMent() {
sugerMachine.setState(sugerMachine.getPaymentState());
System.out.println("支付成功,继续操作");
}
@Override
public void ejectMoney() {
System.out.println("没有支付");
}
@Override
public void turnButton() {
System.out.println("没钱,按了没用~~");
}
@Override
public void grantSuger() {
System.out.println("没钱,不给你糖");
}
}
class PaymentState implements State{
private SugerMachine sugerMachine;
public PaymentState(SugerMachine sugerMachine) {
this.sugerMachine=sugerMachine;
}
@Override
public void payMent() {
System.out.println("已经支付,不需要支付");
}
@Override
public void ejectMoney() {
sugerMachine.setState(sugerMachine.getNoPaymentState());
System.out.println("退钱成功,返回未支付状态");
}
@Override
public void turnButton() {
sugerMachine.setState(sugerMachine.getSoldState());
System.out.println("正在处理");
}
@Override
public void grantSuger() {
System.out.println("当前不支持");
}
}
class SoldState implements State{
private SugerMachine sugerMachine;
public SoldState(SugerMachine sugerMachine){
this.sugerMachine=sugerMachine;
}
@Override
public void payMent() {
System.out.println("当前不允许支付");
}
@Override
public void ejectMoney() {
System.out.println("当前不允许退钱");
}
@Override
public void turnButton() {
System.out.println("当前不允许按按钮");
}
@Override
public void grantSuger() {
int count=sugerMachine.getCount();
if (count>0){
System.out.println("给你,糖果~~");
sugerMachine.setState(sugerMachine.getNoPaymentState());
}else{
sugerMachine.setState(sugerMachine.getOutAgeState());
System.out.println("糖果没了,抱歉");
}
}
}
class OutAgeState implements State{
private SugerMachine sugerMachine;
public OutAgeState(SugerMachine sugerMachine) {
this.sugerMachine = sugerMachine;
}
@Override
public void payMent() {
System.out.println("当前不支持");
}
@Override
public void ejectMoney() {
System.out.println("当前不支持");
}
@Override
public void turnButton() {
System.out.println("当前不支持");
}
@Override
public void grantSuger() {
System.out.println("当前不支持");
}
}
public class State1Test {
public static void main(String args[]){
SugerMachine sugerMachine=new SugerMachine(5);
sugerMachine.payMent();
sugerMachine.ejectMeney();
sugerMachine.payMent();
sugerMachine.trunMoney();
}
}
输出:
支付成功,继续操作
退钱成功,返回未支付状态
支付成功,继续操作
正在处理
给你,糖果~~
五、总结:
通过状态模式,在扩展新功能的时候,只需要添加新的状态类即可,实现了对扩展开放,对修改关闭的原则。
将各种状态的转换放在子类中实现,减少了互相的依赖。但造成很多子类的生成。