状态模式

状态模式允许在内部状态时改变它的行为,在外部看起来好像修改了类。状态模式可以延伸出状态机的概念,状态机据我自己所知在电商系统中用来控制订单状态的流转。关于状态机,大家可以在评论中可以补充一下(状态机的更多应用场景)。

类图

  1. State:该类通常是一个接口或者抽象类,具体视情况而定
  2. ConcreteState:具体的状态类,实现状态的控制
  3. Context:具体需要使用状态的客户段,在其内部通常有各个状态的引用以及一个当前状态的引用,当调用handle方法时,其实将方法的调用转发给给当前状态的handle方法去执行

场景模拟

下面我们模拟一个糖果机的场景,在该场景中我们简化了部分逻辑,毕竟我们只是为了了解学习状态模式,而不是实现一个真正的糖果机系统。下面我们分析一下糖果机的场景。首先我们需要一台糖果机,其次该机器有以下集中状态,待投币状态,已投币状态,售出糖果状态,售空状态。下面我们开始我们的状态分析,首先我们需要一个State接口。

State接口

该接口主要有以下方法,投币、退币、摇动手柄、售出糖果,上面这四个方法会改变糖果机的状态。

public interface State {

    void insertQuarter();

    void ejectQuarter();

    void turnCrank();

    void dispense();
}
NoQuarterState类(待投币状态)

在糖果机在待投币状态下,我们唯一能对糖果机做的操作就是投入硬币,当投入硬币之后我们的糖果机就变成了已投币状态。

public class NoQuarterState implements State {

    private GumballMachine gumballMachine;

    public NoQuarterState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }

    @Override
    public void insertQuarter() {
        System.out.println("You insert a quarter!");
        gumballMachine.setCurrentState(gumballMachine.getHasQuarterState());
    }

    @Override
    public void ejectQuarter() {
        throw new UnsupportedOperationException();
    }

    @Override
    public void turnCrank() {
        throw new UnsupportedOperationException();
    }

    @Override
    public void dispense() {
        throw new UnsupportedOperationException();
    }
}
HasQuarterState类(已投币状态)

在糖果机有币的状态下我们可以做两种操作,一种选择退出硬币(待投币状态),还有一种就是摇动摇杆去获得糖果(售出糖果状态)。

public class HasQuarterState implements State {

    private GumballMachine gumballMachine;

    public HasQuarterState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }

    @Override
    public void insertQuarter() {
        throw new UnsupportedOperationException();
    }

    @Override
    public void ejectQuarter() {
        System.out.println("You eject a quarter!");
        gumballMachine.setCurrentState(gumballMachine.getNoQuarterState());
    }

    @Override
    public void turnCrank() {
        System.out.println("You turn this crank!");
        gumballMachine.setCurrentState(gumballMachine.getSoldState());
    }

    @Override
    public void dispense() {
        throw new UnsupportedOperationException();
    }
}
SoldState(售出糖果状态)

在该状态下,我们需要将糖果给用户,因此我们调用糖果机的售出糖果方法,此时我们需要判断糖果机里是否还有糖果,如果没有糖果了我们就将糖果机置为售空状态(等待工作人员补充糖果后糖果机才可以被再次使用),如果还有糖果我们就将糖果机置为待投币状态,等待下一个用户。

public class SoldState implements State {

    private GumballMachine gumballMachine;

    public SoldState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }

    @Override
    public void insertQuarter() {
        throw new UnsupportedOperationException();
    }

    @Override
    public void ejectQuarter() {
        throw new UnsupportedOperationException();
    }

    @Override
    public void turnCrank() {
        throw new UnsupportedOperationException();
    }

    @Override
    public void dispense() {
        gumballMachine.releaseBall();
        if (gumballMachine.getCount() > 0) {
            gumballMachine.setCurrentState(gumballMachine.getNoQuarterState());
        } else {
            gumballMachine.setCurrentState(gumballMachine.getSoldOutState());
        }
    }
}
SoldOutState(售空状态)

在售空状态下我们无法做任何操作。

public class SoldOutState implements State {

    private GumballMachine gumballMachine;

    public SoldOutState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }

    @Override
    public void insertQuarter() {
        throw new UnsupportedOperationException();
    }

    @Override
    public void ejectQuarter() {
        throw new UnsupportedOperationException();
    }

    @Override
    public void turnCrank() {
        throw new UnsupportedOperationException();
    }

    @Override
    public void dispense() {
        throw new UnsupportedOperationException();
    }
}
GumballMachine(糖果机)

有了状态的控制,我们当然要有台糖果机。在糖果机中,我们有四个状态和糖果机当前状态的引用,你会发现我们只是将请求委托给了糖果机的当前状态去实现。

public class GumballMachine {

    private NoQuarterState noQuarterState;

    private HasQuarterState hasQuarterState;

    private SoldState soldState;

    private SoldOutState soldOutState;

    private State currentState;

    private int count;

    public GumballMachine(int count) {
        this.noQuarterState = new NoQuarterState(this);
        this.hasQuarterState = new HasQuarterState(this);
        this.soldState = new SoldState(this);
        this.soldOutState = new SoldOutState(this);
        this.count = count;
        currentState = noQuarterState;
    }

    public GumballMachine(State currentState) {
        this.currentState = currentState;
    }

    public void setCurrentState(State currentState) {
        this.currentState = currentState;
    }

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

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

    public void turnCrank() {
        currentState.turnCrank();
        dispense();
    }

    public void dispense() {
        currentState.dispense();
    }


    public void releaseBall() {
        System.out.println("A gumball comes rolling out the slot...");
        if (count != 0) {
            count -= 1;
        }
    }

    public NoQuarterState getNoQuarterState() {
        return noQuarterState;
    }

    public HasQuarterState getHasQuarterState() {
        return hasQuarterState;
    }

    public SoldState getSoldState() {
        return soldState;
    }

    public SoldOutState getSoldOutState() {
        return soldOutState;
    }

    public int getCount() {
        return count;
    }
}
测试糖果机

一切准备就绪,是时候测试我们的糖果机了。至于下面的结果大家自己去跑测试吧。

public class GumballMachineTest {

    public static void main(String[] args) {
        GumballMachine gumballMachine = new GumballMachine(2);
        gumballMachine.insertQuarter();
        gumballMachine.turnCrank();

        System.out.println("------------------------------");

        gumballMachine.insertQuarter();
        gumballMachine.turnCrank();

        System.out.println("------------------------------");

        gumballMachine.insertQuarter();
        gumballMachine.turnCrank();


        System.out.println("------------------------------");

        gumballMachine.insertQuarter();
        gumballMachine.turnCrank();
    }
}

本文分享自微信公众号 - shysh95(shysh95),作者:shysh95

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-12-15

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • ZkClient使用

    使用原生的Zookeeper API来与Zookeeper服务端进行交互还是比较繁琐复杂的,为了简化这些操作,就诞生了一些封装客户端。这些客户端除了简单易用,还...

    shysh95
  • RabbitMQ基础使用

    生产消息的应用,生产者需要指定将消息发送到哪个exchange,并且指定routingkey(这是为了exchange可以将消息路由到相关的队列)。

    shysh95
  • RabbitMQ镜像队列

    镜像队列主要有两种类型:master和slave。master和slave节点位于同一个集群中。master只要一个节点,slave可以有多个节点。

    shysh95
  • 设计模式六大原则——单一职责原则(SRP)

          就一个类而言,应该仅有一个引起它变化的原因。通俗的说,一个类只负责一项职责。

    令仔很忙
  • 使用C# (.NET Core) 实现状态设计模式 (State Pattern)

    solenovex
  • 单元测试时候使用[ClassInitialize]会该方法必须是静态的公共方法,不返回值并且应采用一个TestContext类型的参数报错的解决办法

    using Microsoft.VisualStudio.TestTools.UnitTesting;

    跟着阿笨一起玩NET
  • asp.net core导出导入excel

    用户6362579
  • Spring框架中的设计模式(四)​

    本文是Spring框架中使用的设计模式第四篇。本文将在此呈现出新的3种模式。一开始,我们会讨论2种结构模式:适配器和装饰器。在第三部分和最后一部分,我们将讨论单...

    程序猿DD
  • (保存)C#基础概念二十五问

    注:本文部份资料来自网络,如有侵权,请与我联系,我会在第一时间声明引用或将其删除!     当初学 C# 时是找个人大概问了一下数据类型和分支语句就开始做项目了...

    用户1172164
  • 【已解决】Xcode代码提示变量为Error Type

    我之前使用Masonry布局时候经常需要设置偏移量,但是呢在设置布局哪里设置死数据不方便进行调试更换就想用一个变量。

    君赏

扫码关注云+社区

领取腾讯云代金券