设计模式之状态模式


前言

大家好,我是练习两年半的Java练习生,最近阅读了《深入浅出设计模式(中文版)》,学习了各种设计模式,所以想出一个专栏和大家分享一下!
如果大家觉得文章还可以,欢迎关注点赞!后续还会陆续更新!!


一、定义

状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。
其中,对象看起来好像修改了它的类 是什么意思呢?从客户的视角来说,如果你使用的对象能够完全改变它的行为,那么你会觉得这个类变了,实际上,这个类只是使用组合通过简单引用不同对象来造成类改变的假象。

二、类图


问: 这个类图与什么模式的类图相似?

这个类图与策略模式的类图一样,但两者区别在于“意图”。
对状态模式来说,我们将一群行为封装在状态对象中,context的行为随时可以委托到状态对象中的一个。随着时间的流逝,当前状态在状态对象集合中游走改变,以反映除context内部的状态。但客户对状态对象了解不多。
而以策略模式而言,客户通常主动指定Context)所要组合的策略对象是哪一个。现在,固然策略模式让我们具有弹性,能够在运行时改变策略,但对于某个context对象来说,通常都只有一个最适当的策略对象。比方说,在前面,有些鸭子(例如绿头鸭)被设置成利用典型的飞翔行为进行飞翔,而有些鸭子(例如橡皮鸭和诱饵鸭)使用的飞翔行为只能让他们紧贴地面。

三、应用

3.1 需求

假设有一个咖啡机,它可以制作两种咖啡:拿铁和美式咖啡。咖啡机的状态分为“空闲状态”、“工作状态”和“维修状态”三种。当咖啡机处于“空闲状态”时,它可以接收用户的订单,并开始制作咖啡。当咖啡机处于“工作状态”时,它正在制作咖啡,此时不能接受新的订单。当咖啡机处于“维修状态”时,它不能接收订单,因为需要进行维护。

3.2 分析

3.3 实现

下面是使用状态模式实现上述场景的示例代码:

// 抽象状态类
public abstract class State {
    protected CoffeeMachine coffeeMachine;

    public State(CoffeeMachine coffeeMachine) {
        this.coffeeMachine = coffeeMachine;
    }

    // 投入硬币
    public abstract void coin();

    // 退回硬币
    public abstract void backCoin();

    // 转动手柄
    public abstract void turnHandle();

    // 出售咖啡
    public abstract void sellCoffee();
}

// 具体状态类:待支付状态
public class NoCoinState extends State {

    public NoCoinState(CoffeeMachine coffeeMachine) {
        super(coffeeMachine);
    }

    @Override
    public void coin() {
        System.out.println("投入了一枚硬币");
        coffeeMachine.setState(coffeeMachine.getCoinInsertedState());
    }

    @Override
    public void backCoin() {
        System.out.println("您没有投入硬币,无法退币");
    }

    @Override
    public void turnHandle() {
        System.out.println("请先投入硬币");
    }

    @Override
    public void sellCoffee() {
        System.out.println("请先投入硬币");
    }
}

// 具体状态类:已支付状态
public class CoinInsertedState extends State {

    public CoinInsertedState(CoffeeMachine coffeeMachine) {
        super(coffeeMachine);
    }

    @Override
    public void coin() {
        System.out.println("您已经投过币了,无需再投");
    }

    @Override
    public void backCoin() {
        System.out.println("退回了一枚硬币");
        coffeeMachine.setState(coffeeMachine.getNoCoinState());
    }

    @Override
    public void turnHandle() {
        System.out.println("转动手柄,出咖啡中...");
        coffeeMachine.setState(coffeeMachine.getSoldState());
    }

    @Override
    public void sellCoffee() {
        System.out.println("请先转动手柄");
    }
}

// 具体状态类:售出状态
public class SoldState extends State {

    public SoldState(CoffeeMachine coffeeMachine) {
        super(coffeeMachine);
    }

    @Override
    public void coin() {
        System.out.println("请等待咖啡出完再投币");
    }

    @Override
    public void backCoin() {
        System.out.println("咖啡已经在制作,无法退币");
    }

    @Override
    public void turnHandle() {
        System.out.println("转动手柄,正在出咖啡,请耐心等待...");
    }

    @Override
    public void sellCoffee() {
        System.out.println("正在出咖啡,请耐心等待...");
        coffeeMachine.setState(coffeeMachine.getNoCoinState());
    }
}

// 咖啡机类,使用状态模式实现
public class CoffeeMachine {
    private State noCoinState;
    private State coinInsertedState;
    private State soldState;

    private State currentState;

    public CoffeeMachine() {
        noCoinState = new NoCoinState(this);
        coinInsertedState = new CoinInsertedState(this);
        soldState = new SoldState(this);

        // 初始状态为未投币状态
        currentState = noCoinState;
   // 初始化咖啡数量
    coffeeCount = 10;
}

// 投币方法
public void insertCoin() {
    currentState.insertCoin();
}

// 退币方法
public void ejectCoin() {
    currentState.ejectCoin();
}

// 购买咖啡方法
public void buyCoffee() {
    currentState.buyCoffee();
}

// 获取当前咖啡数量
public int getCoffeeCount() {
    return coffeeCount;
}

// 减少咖啡数量
public void decreaseCoffeeCount() {
    coffeeCount--;
}

// 切换状态为未投币状态
public void setCurrentStateToNoCoinState() {
    currentState = noCoinState;
}

// 切换状态为已投币状态
public void setCurrentStateToCoinInsertedState() {
    currentState = coinInsertedState;
}

// 切换状态为售出状态
public void setCurrentStateToSoldState() {
    currentState = soldState;
}
}

四、问题

客户会直接与状态交互吗?

答:不会。状态是用在Context中来代表它的内部状态以及行为的,所以只有Context才会对状态提出求。客户不会直接改变Context的状态。全盘了解状态是Context的工作,客户根本不了解,所以不会直接和状态联系。

如果在我的程序中Context有许多实例,这些实例之间可以共享状态对象吗?

是的,绝对可以,事实上这是很常见的做法。但唯一的前提是,你的状态对象不能持有它们自己的内部状态;否则就不能共享。想要共享状态,你需要把每个状态都指定到静态的实例变量中。如果你的状态需要利用到Context中的方法或者实例变量,你还必须在每个handler()方法内传入一个context的引用。


五、总结

以上就是今天要讲的内容,本文介绍了设计模式中的状态模式,要注意其与策略模式的区别,两者的目的并不相同。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值