• 设计模式行为型-状态模式


    简介

    • 状态模式是一种行为型设计模式,用于处理对象在不同状态下的行为变化。它将对象的行为封装在不同状态类中,通过状态的切换实现不同行为的触发。
    • 本文将介绍状态模式的基本概念、应用场景以及优势与适用性。
      在这里插入图片描述

    状态模式基础

    定义状态接口或抽象类

    public abstract class State
        {
            public abstract void WriteProgram(Work w);
        }
    
    • 1
    • 2
    • 3
    • 4

    实现具体状态类

        //上午工作状态
        public class ForenoonState : State
        {
            public override void WriteProgram(Work w)
            {
    //这里的判断就是决定要用那种行为展现出来,如果 不符合当前状态,那么就去到已经设置好的下一个具体状态类中进行相同的操作。
                if (w.hour < 12)
                {
                    Console.WriteLine("当前时间:{0}点 上午工作,精神百倍",w.Hour);
                }
                else
                {
                    w.SetState(new NoonState());w.WriteProgram();
                }
            }
        }
        //中午工作状态
        public class NoonState : State
        {
            public override void WriteProgram(Work w)
            {
                if (w.hour < 13)
                {
                    Console.WriteLine("当前时间:{0}点 饿了,想吃饭;犯困,想睡觉。", w.Hour);
                }
                else
                {
                    w.SetState(new AfternoonState()); w.WriteProgram();
                }
            }
        }
        //下午工作状态
        public class AfternoonState : State
        {
            public override void WriteProgram(Work w)
            {
                if (w.hour < 17)
                {
                    Console.WriteLine("当前时间:{0}点 下午状态还不错,继续努力", w.Hour);
                }
                else
                {
                    w.SetState(new EveningState()); w.WriteProgram();
                }
            }
        }
        //晚上工作状态
        public class EveningState : State
        {
            public override void WriteProgram(Work w)
            {
                if (w.finish )
                {
                    w.SetState(new RestState());w.WriteProgram();//完成任务就转成下班状态
                }
                else
                {
                    if (w.hour <21)
                    {
                        Console.WriteLine("当前时间:{0}点 加班了,加班人累啊", w.Hour);
                    }
                    else 
                    {
                        w.SetState(new SleepingState()); w.WriteProgram();//超过21点,转入睡眠状态
                    }
                }
            }
        }
    
        //睡眠状态
        public class SleepingState:State
        {
            public override void WriteProgram(Work w)
            {
                Console.WriteLine("当前时间:{0}点 不行了,睡着了", w.Hour);
            }
        }
        //下班休息状态
        public class RestState : State
        {
            public override void WriteProgram(Work w)
            {
                Console.WriteLine("当前时间:{0}点 不行了,睡着了", w.Hour);
            }
        }
    
    • 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
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85

    具体工作类:

        public class Work
        {
            public State current;
            
            public Work()
            {
                current = new ForenoonState();	//初始化为上午9点开始上班
            }
            public double hour;//小时钟,状态转换的依据
    
            public bool finish = false;//完成任务属性,是否能下班的依据
     
     
    //这个方法主要就是把具体的状态类给进来,然后让下面的方法去使用
            public void SetState(State s)	//得到状态
            {
                current = s;
            }
    //下面这个方法从始至终都没有发生改变,改变是其内部具体的展现值。
            public void WriteProgram() 
            {
                current.WriteProgram(this);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    上下文类与状态转换

    上下文类的定义和作用

    • 上下文类包含状态对象的引用,并将具体行为委托给当前状态对象执行。
    • 示例代码:
    // 上下文类
    public class Context {
        private State currentState;
    
        public void setCurrentState(State state) {
            this.currentState = state;
        }
    
        public void request() {
            // 委托当前状态对象执行行为
            currentState.handle();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    状态转换及触发条件

    • 状态转换指从一个状态切换到另一个状态的过程。
    • 触发条件是使状态转换发生的条件。
    • 示例代码:
    // 具体状态类A
    public class ConcreteStateA implements State {
        // ...
    
        @Override
        public void handle() {
            // 具体状态A的行为逻辑
    
            // 状态转换及触发条件
            if (/*触发条件*/) {
                context.setCurrentState(new ConcreteStateB());
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    状态模式的优势与适用性

    优点一:可维护的代码

    • 状态模式将每个状态的行为逻辑封装在独立的状态类中,易于理解和维护。

    优点二:清晰的状态管理

    • 状态模式通过上下文类进行状态转换和行为委托,使状态管理更加清晰明确。

    适用场景一:对象拥有多个状态

    • 当对象具有多个状态且不同状态下表现出不同行为时,可以使用状态模式进行状态管理和行为切换。

    适用场景二:状态转换频繁且复杂

    • 当状态转换频繁且存在复杂的触发条件时,状态模式能够提供一种结构化的方式来管理状态转换。

    具体业务场景应用:电商订单状态切换


    为了演示订单状态管理的状态模式业务代码,我将使用Java语言来实现。以下是一个简单的示例:

    首先,我们定义订单状态接口 OrderState,其中包含了处理订单状态的方法 handle()

    // 订单状态接口
    public interface OrderState {
        void handle();
    }
    
    • 1
    • 2
    • 3
    • 4

    然后,我们创建具体的订单状态类,包括待支付状态、已支付状态、待发货状态和已发货状态。每个状态类实现了订单状态接口,并根据相应的状态实现了自己的行为逻辑。

    // 待支付状态类
    public class PendingPaymentState implements OrderState {
        @Override
        public void handle() {
            System.out.println("当前订单状态:待支付");
            // 处理待支付状态的逻辑
        }
    }
    
    // 已支付状态类
    public class PaidState implements OrderState {
        @Override
        public void handle() {
            System.out.println("当前订单状态:已支付");
            // 处理已支付状态的逻辑
        }
    }
    
    // 待发货状态类
    public class ToBeShippedState implements OrderState {
        @Override
        public void handle() {
            System.out.println("当前订单状态:待发货");
            // 处理待发货状态的逻辑
        }
    }
    
    // 已发货状态类
    public class ShippedState implements OrderState {
        @Override
        public void handle() {
            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
    • 33
    • 34
    • 35

    接下来,我们创建订单类 Order,它包含了当前订单状态和一些操作方法。

    // 订单类
    public class Order {
        private OrderState currentState; // 当前订单状态
    
        public Order() {
            currentState = new PendingPaymentState(); // 默认初始状态为待支付
        }
    
        public void setCurrentState(OrderState state) {
            currentState = state;
        }
    
        public void request() {
            currentState.handle();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    最后,我们可以进行测试,模拟订单在不同状态下的行为变化:

    public class Main {
        public static void main(String[] args) {
            Order order = new Order(); // 创建订单
    
            // 待支付状态
            order.request();
    
            // 支付订单,状态转换为已支付
            order.setCurrentState(new PaidState());
            order.request();
    
            // 发货,状态转换为待发货
            order.setCurrentState(new ToBeShippedState());
            order.request();
    
            // 完成发货,状态转换为已发货
            order.setCurrentState(new ShippedState());
            order.request();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    运行以上代码,将得到如下输出:
    在这里插入图片描述

    以上示例演示了订单状态管理的状态模式业务代码。通过状态模式,我们可以根据订单状态的变化触发不同的行为逻辑,并且可以方便地添加新的订单状态,以满足业务需求。

    状态模式与其他设计模式的结合

    策略模式与状态模式的对比与联系

    策略模式和状态模式都属于行为型设计模式,它们都关注对象在不同的情境下具有不同的行为。虽然它们有相似之处,但在设计意图、应用场景和实现方式上存在一些差异。

    下面是策略模式和状态模式的对比与联系:

    对比:

    1. 设计意图:策略模式旨在通过定义一组算法或策略,并将其封装成独立的对象,使得这些算法可以互换使用。状态模式旨在让一个对象在其内部状态改变时改变其行为,从而实现状态之间的转换。

    2. 关注点:策略模式主要关注算法的选择和封装,使得具体的策略可以独立于客户端进行变化。状态模式主要关注对象的状态的管理和转换,以及不同状态下的行为执行。

    3. 对象角色:策略模式通常包含一个上下文类(Context)和一组策略类(Strategies),客户端与上下文类进行交互。状态模式通常包含一个上下文类(Context)和一组状态类(States),客户端与上下文类进行交互。

    联系:

    1. 行为的封装:策略模式和状态模式都将行为封装到独立的对象中,使得行为可以被动态地变化。

    2. 对象之间的互动:策略模式和状态模式都需要一个上下文类(Context)来与策略对象或状态对象进行交互,并将具体的行为委托给策略对象或状态对象来执行。

    3. 可扩展性:策略模式和状态模式都具有较好的可扩展性。在策略模式中,可以方便地新增、修改或切换不同的策略对象。在状态模式中,可以方便地新增、修改或切换不同的状态对象。

    总的来说,策略模式和状态模式都是强调对象行为的灵活性和可扩展性的设计模式。它们的主要区别在于策略模式关注算法的选择和封装,而状态模式关注对象状态的管理和转换。根据具体的需求,选择适合的模式来提高代码的可维护性和可扩展性。

    工厂模式与状态模式的结合实践

    • 结合工厂模式可以实现状态类的动态创建和切换,增强了状态模式的灵活性和可扩展性。
      结合工厂模式可以实现状态类的动态创建和切换,从而增强了状态模式的灵活性和可扩展性。工厂模式可以将状态对象的创建和状态转换逻辑与客户端代码分离,使得系统更加可维护和可扩展。

    下面是一个示例,演示了如何结合工厂模式和状态模式来管理订单的状态:

    首先,定义订单状态接口 OrderState 和具体的订单状态类,与之前的示例相同。

    // 订单状态接口
    public interface OrderState {
        void handle();
    }
    
    // 待支付状态类
    public class PendingPaymentState implements OrderState {
        @Override
        public void handle() {
            System.out.println("当前订单状态:待支付");
            // 处理待支付状态的逻辑
        }
    }
    
    // 已支付状态类
    public class PaidState implements OrderState {
        @Override
        public void handle() {
            System.out.println("当前订单状态:已支付");
            // 处理已支付状态的逻辑
        }
    }
    
    // 待发货状态类
    public class ToBeShippedState implements OrderState {
        @Override
        public void handle() {
            System.out.println("当前订单状态:待发货");
            // 处理待发货状态的逻辑
        }
    }
    
    // 已发货状态类
    public class ShippedState implements OrderState {
        @Override
        public void handle() {
            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
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    然后,创建一个工厂类 OrderStateFactory,用于动态创建订单状态对象。
    在严格意义上这个工厂是一个不支持扩充的,但是在这里仅作为一个示例,如果想要真正达到动态创建还是需要用到工厂方法,这里只能算是一个简单工厂。

    // 订单状态工厂类  
    public class OrderStateFactory {
        public static OrderState createOrderState(String stateName) {
            switch (stateName.toLowerCase()) {
                case "pendingpayment":
                    return new PendingPaymentState();
                case "paid":
                    return new PaidState();
                case "tobeshipped":
                    return new ToBeShippedState();
                case "shipped":
                    return new ShippedState();
                default:
                    throw new IllegalArgumentException("Invalid state name");
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    接下来,我们可以使用上述的状态类和工厂类进行订单状态切换的实践:

    public class Main {
        public static void main(String[] args) {
            Order order = new Order(); // 创建订单
    
            // 设置待支付状态
            order.setCurrentState(OrderStateFactory.createOrderState("PendingPayment"));
            order.request();
    
            // 支付订单,切换到已支付状态
            order.setCurrentState(OrderStateFactory.createOrderState("Paid"));
            order.request();
    
            // 发货,切换到待发货状态
            order.setCurrentState(OrderStateFactory.createOrderState("ToBeShipped"));
            order.request();
    
            // 完成发货,切换到已发货状态
            order.setCurrentState(OrderStateFactory.createOrderState("Shipped"));
            order.request();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    通过工厂模式,我们可以根据状态名称动态地创建不同的订单状态对象,并将其设置为上下文类的当前状态。这样,如果要新增或修改订单状态,只需要修改工厂类的代码,而不需要修改客户端的代码。这增强了状态模式的灵活性和可扩展性。

    总结

    • 状态模式是一种有助于管理对象不同状态下行为变化的设计模式。通过将状态和行为封装在不同状态类中,状态模式提供了一种结构化的方式来处理状态转换和行为委托。它适用于对象拥有多个状态且状态转换复杂的场景,并与其他设计模式如策略模式、工厂模式等相结合能够进一步扩展其功能和灵活性。
  • 相关阅读:
    RabbitMQ的幂等性、优先级队列和惰性队列
    python 端口快速扫描
    Linux C : select简介和epoll 实现
    Go 代码包与引入:如何有效组织您的项目
    路由进阶:route-policy实验配置
    揭开并大三大问题之可见性问题的神秘面纱
    vue 动态绑定ref 父组件获取自组件data数据
    洗地机哪个牌子好用又实惠?口碑最好的洗地机推荐
    常用的OLED透明显示屏款式,有几种?
    【Linux篇】之Squid代理服务器配置
  • 原文地址:https://blog.csdn.net/pengjun_ge/article/details/132590068