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

news/2025/2/22 20:31:13/

文章目录

  • 简介
  • 状态模式基础
    • 定义状态接口或抽象类
      • 实现具体状态类
  • 上下文类与状态转换
    • 上下文类的定义和作用
    • 状态转换及触发条件
  • 状态模式的优势与适用性
    • 优点一:可维护的代码
    • 优点二:清晰的状态管理
    • 适用场景一:对象拥有多个状态
    • 适用场景二:状态转换频繁且复杂
  • 具体业务场景应用:电商订单状态切换
  • 状态模式与其他设计模式的结合
    • 策略模式与状态模式的对比与联系
    • 工厂模式与状态模式的结合实践
  • 总结

简介

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

状态模式基础

定义状态接口或抽象类

public abstract class State{public abstract void WriteProgram(Work w);}

实现具体状态类

    //上午工作状态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);}}

具体工作类:

    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);}}

上下文类与状态转换

上下文类的定义和作用

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

状态转换及触发条件

  • 状态转换指从一个状态切换到另一个状态的过程。
  • 触发条件是使状态转换发生的条件。
  • 示例代码:
// 具体状态类A
public class ConcreteStateA implements State {// ...@Overridepublic void handle() {// 具体状态A的行为逻辑// 状态转换及触发条件if (/*触发条件*/) {context.setCurrentState(new ConcreteStateB());}}
}

状态模式的优势与适用性

优点一:可维护的代码

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

优点二:清晰的状态管理

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

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

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

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

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

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


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

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

// 订单状态接口
public interface OrderState {void handle();
}

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

// 待支付状态类
public class PendingPaymentState implements OrderState {@Overridepublic void handle() {System.out.println("当前订单状态:待支付");// 处理待支付状态的逻辑}
}// 已支付状态类
public class PaidState implements OrderState {@Overridepublic void handle() {System.out.println("当前订单状态:已支付");// 处理已支付状态的逻辑}
}// 待发货状态类
public class ToBeShippedState implements OrderState {@Overridepublic void handle() {System.out.println("当前订单状态:待发货");// 处理待发货状态的逻辑}
}// 已发货状态类
public class ShippedState implements OrderState {@Overridepublic void handle() {System.out.println("当前订单状态:已发货");// 处理已发货状态的逻辑}
}

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

// 订单类
public class Order {private OrderState currentState; // 当前订单状态public Order() {currentState = new PendingPaymentState(); // 默认初始状态为待支付}public void setCurrentState(OrderState state) {currentState = state;}public void request() {currentState.handle();}
}

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

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

联系:

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

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

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

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

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

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

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

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

// 订单状态接口
public interface OrderState {void handle();
}// 待支付状态类
public class PendingPaymentState implements OrderState {@Overridepublic void handle() {System.out.println("当前订单状态:待支付");// 处理待支付状态的逻辑}
}// 已支付状态类
public class PaidState implements OrderState {@Overridepublic void handle() {System.out.println("当前订单状态:已支付");// 处理已支付状态的逻辑}
}// 待发货状态类
public class ToBeShippedState implements OrderState {@Overridepublic void handle() {System.out.println("当前订单状态:待发货");// 处理待发货状态的逻辑}
}// 已发货状态类
public class ShippedState implements OrderState {@Overridepublic void handle() {System.out.println("当前订单状态:已发货");// 处理已发货状态的逻辑}
}

然后,创建一个工厂类 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");}}
}

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

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();}
}

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

总结

  • 状态模式是一种有助于管理对象不同状态下行为变化的设计模式。通过将状态和行为封装在不同状态类中,状态模式提供了一种结构化的方式来处理状态转换和行为委托。它适用于对象拥有多个状态且状态转换复杂的场景,并与其他设计模式如策略模式、工厂模式等相结合能够进一步扩展其功能和灵活性。

http://www.ppmy.cn/news/1074393.html

相关文章

CSS伪类

目录 一、概念及语法 二、伪类的使用 ① 锚伪类&#xff1a;链接能够以不同的方式显示 ② 伪类和 CSS 类 ③ 悬停在 div上 ④ 简单的工具提示悬停 ⑤ CSS - :first-child 伪类 ⑥ 匹配所有 元素中的首个 元素 ⑦ 匹配所有首个 元素中的所有 元素 ⑧ CSS - :lang 伪类 一、概念…

vue面试题_vue2和vue3的区别

1、数据绑定原理不同 vue2&#xff1a;vue2的数据绑定是利用ES5的一个API&#xff1a;Object.definePropert() 对数据进行劫持&#xff0c;结合发布订阅模式的方式来实现的。 vue3&#xff1a;vue3中使用了ES6的Proxy API对数据代理。相比vue2.x&#xff0c;使用proxy的优势如…

【超详细~KVM】KVM概述、安装及简单操作-------从小白到大神之路之学习运维第91天

第四阶段提升 时 间&#xff1a;2023年8月30日 参加人&#xff1a;全班人员 内 容&#xff1a; KVM概述、安装及简单操作 目录 一、KVM 概述 二、KVM工作原理 三、KVM应用场景 四、centos7 下安装部署 五、新建虚拟机步骤 1、创建存储池并创建存储卷 2、点击号创建…

el-table表尾添加合计行,自动合计,且特殊列自定义计算展示

效果如图 1.element-ui的table表格有合计功能&#xff0c;但是功能却不完善&#xff0c;会有不显示和计算出现错误的问题&#xff0c;项目中有遇到&#xff0c;所以记录下 show-summary&#xff1a;自动合计 getSummaries&#xff08;&#xff09;&#xff1a;对合计行进行特…

会不会激发对modern c++的新兴趣

可变参数好像很厉害的样子&#xff0c;会节省很多手写代码&#xff0c;让编译器自动帮我们生成代码 template<typename Fun, typename...Args> void invoke(Fun&& fun, Args&&...args) { fun(std::forward<Args>(args)...); } 任意函数包装器…

nginx的try_files指令遇到vue-router history 模式

这里记录一下这个知识点&#xff0c;之前也没有特意对这个这个知识点做过汇总 问ChatGPT&#xff1a; 你详细解释下try_files 指令&#xff1f; ChatGPT回答&#xff1a; 当Nginx处理客户端请求时&#xff0c;try_files 指令用于按照指定的顺序尝试查找文件&#xff0c;并在…

AutoCAD图如何保存为Word

AutoCAD图如何保存为Word 引言AutoCAD图保存为Word文件步骤&#xff1a; 引言 不知道大家有没有是否遇到需要将AutoCAD图保存到Word中。有些小伙伴可能直接截图插入Word中&#xff0c;这种方法简单&#xff0c;但对于有高清图片需求的小伙伴就不适用了。接下来我就为大家介绍一…

华为 连接OSPF和RIP网络---OSPF和RIP网络相互引入

路由引入简介 不同路由协议之间不能直接共享各自的路由信息&#xff0c;需要依靠配置路由的引入来实现。 获得路由信息一般有3种途径&#xff1a;直连网段、静态配置和路由协议。可以将通过这3种途径获得的路由信息引入到路由协议中&#xff0c;例如&#xff0c;把直连网段引入…