• 状态模式(状态和行为分离)


    状态模式

    什么是状态模式

    状态模式(State),当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类

    状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断
    逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化。当然,如果这个状态判断很简
    单,那就没必要用‘状态模式了

    • Context:维护一个ConcreteState子类的实例,这个实例定义当前的状态
    • State:抽象状态类,定义一个接口以封装与Context的一个特定状态相关的行为
    • 抽象状态类,定义一个接口以封装与Context的一个特定状态相关的行为

    状态模式好处与用处

    状态模式的好处是将与特定状态相关的行为局部化,并且将不同状态的行为分割开来

    将特定的状态相关的行为都放入一个对象中,由于所有与状态相关的代码都存在于某个ConcreteState中,所以通过定义新的子类可以很容易地增加新的状态和转换

    这样做的目的就是为了消除庞大的条件分支语句,大的分支判断会使得它们难以修改和扩展,就像我们最早说的刻版印刷一样,任何改动和变化都是致命的。状态模式通过把各种状态转移逻辑分布到State的子类之间,来减少相互间的依赖,好比把整个版面改成了一个又一个的活字,此时就容易维护和扩展了

    什么时候考虑使用状态模式

    当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时,就可以考虑使用状态模式了

    通过示例了解状态模式

    状态模式是一种行为设计模式,它允许一个对象在其内部状态改变时改变其行为。这种模式将对象的状态与其行为解耦,使得状态的变化不影响对象接口。下面是一个使用 Java 实现状态模式的示例,以一个自动售货机为例,它具有不同的硬币投入状态,并根据当前状态决定是否接受硬币、是否可以购买商品以及找零等行为。

    1.首先,定义一个 VendingMachineState 抽象类(或接口),声明所有可能的状态行为:

    public abstract class VendingMachineState {
        protected VendingMachine vendingMachine; // 售货机对象,用于状态切换
    
        public VendingMachineState(VendingMachine vendingMachine) {
            this.vendingMachine = vendingMachine;
        }
    
        // 抽象方法,由子类实现具体的业务逻辑
        public abstract void insertCoin(int amount); // 投入硬币
        public abstract void ejectCoin(); // 取消投币
        public abstract void selectProduct(String product); // 选择商品
        public abstract void dispenseProduct(); // 出货
        public abstract void giveChange(); // 找零
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2.接下来,为自动售货机创建几种具体的状态类,每种状态类继承自 VendingMachineState 并实现其抽象方法:

    public class NoCoinState extends VendingMachineState {
        public NoCoinState(VendingMachine vendingMachine) {
            super(vendingMachine);
        }
    
        @Override
        public void insertCoin(int amount) {
            System.out.println("接受硬币 " + amount + " 元");
            vendingMachine.setState(new HasCoinState(vendingMachine)); // 改变状态为已投币状态
        }
    
        // 其他方法的实现,由于当前状态无硬币,通常拒绝执行相关操作
        @Override
        public void ejectCoin() {
            System.out.println("未投币,无法取消");
        }
    
        @Override
        public void selectProduct(String product) {
            System.out.println("请先投入硬币");
        }
    
        @Override
        public void dispenseProduct() {
            System.out.println("请先投入硬币并选择商品");
        }
    
        @Override
        public void giveChange() {
            System.out.println("请先完成购买");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    public class HasCoinState extends VendingMachineState {
        public HasCoinState(VendingMachine vendingMachine) {
            super(vendingMachine);
        }
    
        @Override
        public void insertCoin(int amount) {
            System.out.println("接受硬币 " + amount + " 元");
        }
    
        // 其他方法的实现,如允许用户选择商品、出货、找零等
        // ...
    }
    
    // 可以根据需要添加更多状态类,如 InsufficientCoinState(金额不足状态)、ProductSelectedState(商品已选状态)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    3.最后,定义 VendingMachine 类,包含状态字段及状态切换的相关方法:

    public class VendingMachine {
        private VendingMachineState state;
    
        public VendingMachine() {
            setState(new NoCoinState(this)); // 初始化状态为无硬币状态
        }
    
        public void setState(VendingMachineState state) {
            this.state = state;
        }
    
        public void insertCoin(int amount) {
            state.insertCoin(amount);
        }
    
        public void ejectCoin() {
            state.ejectCoin();
        }
    
        public void selectProduct(String product) {
            state.selectProduct(product);
        }
    
        public void dispenseProduct() {
            state.dispenseProduct();
        }
    
        public void giveChange() {
            state.giveChange();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    4.现在,您可以创建一个 VendingMachine 对象并模拟用户的操作:

    public class Main {
        public static void main(String[] args) {
            VendingMachine vendingMachine = new VendingMachine();
    
            vendingMachine.insertCoin(5); // 投入5元硬币
            vendingMachine.selectProduct("Coke"); // 选择可乐
            vendingMachine.insertCoin(3); // 再投入3元硬币
            vendingMachine.dispenseProduct(); // 出货
            vendingMachine.giveChange(); // 找零
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这个示例中,VendingMachine 类依赖于其内部状态对象(VendingMachineState 的子类)来决定如何响应外部事件。当状态发生变化时,VendingMachine 会切换到相应的新状态对象,从而改变其行为。通过这种方式,状态模式实现了状态与行为的分离,使得状态转换和状态相关行为的增加变得容易且灵活。

  • 相关阅读:
    Java后端入职第四天,就被要求代码回退(Git回退实战)
    技术学习:Python(14)|爬虫requests库
    [网络] 前端大文件上传
    Redis主从复制
    科学高效备考AMC8和AMC10竞赛,吃透2000-2024年1850道真题和解析
    mongodb 6/7的 windows安装问题
    wpf工程中加入Hardcodet.NotifyIcon.Wpf生成托盘
    模型训练前后显卡占用对比、多卡训练GPU占用分析【一文读懂】
    Arduino基础知识
    MyBatis笔记
  • 原文地址:https://blog.csdn.net/LuckFairyLuckBaby/article/details/137905088