设计模式(十一)—— 状态模式

一、含义

允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。也就是说当一个对象有许多状态的时候,我们可以把每个对象抽离出来作为一个具体的类。

二、要点

1.状态模式允许一个对象基于内部状态而拥有不同的行为。

2.通过将每个状态封装进一个类,我们把以后需要做的任何改变局部化了。

3.使用状态模式通常会导致设计中类的数目大量增加。

三、实战分析外观模式

首先看一下状态模式的类图:

例如现在有需要自动售货机,现在假设一个自动售货机只卖一种饮料,只需5块钱,对于售货机有四种状态就是,没有投钱,投入5块钱,出售饮料,饮料售空。现在让我们用代码,来编写自动售货机这个收获流程:

public class DrinksMachine {
    
    //对应自动售货机的四种状态
    final static int SOLD_OUT = 0;
    
    final static int NO_QUARTER = 1;
    
    final static int HAS_QUARTER = 2;
    
    final static int SOLD = 3;
    
    //记录当前状态
    int state = SOLD_OUT;
    
    //记录饮料数目
    int count = 0;

    public DrinksMachine(int count) {
        this.count = count;
        if (count > 0) {
            state = NO_QUARTER;
        }
    }
    
    //当我们投入5块钱时,会执行这个方法
    public void insertQuarter() {
        if (state == HAS_QUARTER) {
            System.out.println("已投钱,请勿重复投币");
        } else if (state == NO_QUARTER) {
            state = HAS_QUARTER;
            System.out.println("投币成功");

        } else if (state == SOLD_OUT) {
            System.out.println("请莫投币,饮料已售空");
        } else if (state == SOLD) {
            System.out.println("请等待,我们正在出货");
        }
    }

    //当我们尝试退款时,执行的方法
    public void ejectQuarter() {
        if (state == HAS_QUARTER) {
            System.out.println("正在退钱,请稍等");
            state = NO_QUARTER;
        } else if (state == NO_QUARTER) {
            System.out.println("未投钱,无法退款");
        } else if (state == SOLD) {
            System.out.println("无法退钱,正在给你出货");
        } else if (state == SOLD_OUT) {
            System.out.println("饮料已售空,未首款");
        }
    }
    
    //当我们按下按钮准备买饮料时,会调用此方法
    public void turnCrank() {
        if (state == SOLD) {
            System.out.println("正在出货请稍等,不要重复按钮");
        } else if (state == NO_QUARTER) {
            System.out.println("还未投钱,请先投钱");
        } else if (state == SOLD_OUT) {
            System.out.println("不好意思,已售空");
        } else if (state == HAS_QUARTER) {
            System.out.println("出货");
            state = SOLD;
            sale();
        }
    }
    
    //出售饮料方法
    public void sale() {

        if (state == SOLD) {
            System.out.println("正在出货");
            count --;
            if (count == 0) {
                System.out.println("已售空");
                state = SOLD_OUT;
            } else {
                state = NO_QUARTER;
            }
        } else if (state == NO_QUARTER) {
            System.out.println("请先投钱");
        } else if (state == SOLD_OUT) {
            System.out.println("饮料已售空");
        } else if (state == HAS_QUARTER) {
            System.out.println("机器故障");
        }
        
    }
}

从上述代码可以看出,我们每个方法都要对售货机的每个状态都要进行判断,这显得代码复用性不高,而且如果我们可以加入新的状态时,我们需要修改大量的代码,这违反了类应该对扩展开放,对修改关闭的原则。这个我们的状态模式就可以大显神威了,利用状态模式,重写这个自动收货机,结合上面的类图,我们需要把每个状态单独封装成一个类,并实现一个共同的接口:

//状态的通用接口
public interface state {
    
    void insertQuarter();
    
    void ejectQuarter();
    
    void turnCrank();
    
    void sale();
}

在编写对应的具体的状态类

//其中的一个例子,其他的三个状态大体相同
public class NoQuarterState implements State {
    DrinksMachine drinksMachine;

    public NoQuarterState(DrinksMachine drinksMachine) {
        this.drinksMachine = drinksMachine;
    }

    //当有人投钱时
    @Override
    public void insertQuarter() {
        System.out.println("你已投钱");
        drinksMachine.setState(drinksMachine.getHasQuarterState());
    }

    @Override
    public void ejectQuarter() {
        System.out.println("你未投钱");
    }

    @Override
    public void turnCrank() {
        System.out.println("没有钱,无法出售");
    }

    @Override
    public void sale() {
        System.out.println("没有钱,无法出售");
    }
}

最后我们在将自己售货机的代码给修改:

public class DrinksMachine {

    //对应着自己状态
    State soldOutState;
    State noQuarterState;
    State hasQuarterState;
    State soldState;

    State state = soldOutState;
    int count = 0;

    public DrinksMachine(int number) {
        soldOutState = new SoldOutState(this);
        noQuarterState = new NoQuarterState(this);
        hasQuarterState = new HasQuarterState(this);
        soldState = new SoldState(this);
        this.count = number;
        if (number > 0) {
            state = noQuarterState;
        }
    }

    public void insertQuarter() {
        state.insertQuarter();
    }

    public void ejectQuarter() {
        state.ejectQuarter();
    }

    public void turnCrank() {
        state.turnCrank();
    }

    public void sale() {
        state.sale();
    }

    //每个状态的get/set方法
}

这看着上就简洁的多,并且在以后有新的状态时,只需添加新的状态类就可以。

猜你喜欢

转载自blog.csdn.net/huxiaodong1994/article/details/84714392
今日推荐