【重温设计模式】状态模式及其Java示例

news2024/11/29 1:32:32

状态模式的基本概念

在编程世界的大海中,各种设计模式就如同灯塔,为我们的代码编写指明方向。其中,状态模式是一种行为设计模式,它让你能在一个对象的内部状态改变时改变其行为,使得对象看起来就像改变了其类一样。这个模式的名字,仿佛是在告诉我们,它就像一个小船,在程序设计的海洋中,根据风向(状态)改变航向(行为)。

状态模式在面向对象设计中的重要性不言而喻,它是我们处理复杂对象状态转换,减少条件语句,使代码更加清晰和易于维护的重要工具。

public class OneMore {
    private State state;
    public OneMore(State state) {
        this.state = state;
    }
    public void setState(State state) {
        this.state = state;
    }
    public void request() {
        state.handle(this);
    }
}

在这段简单的Java代码中,我们定义了一个名为OneMore的类,这个类有一个状态(State)属性,通过改变这个状态,OneMore的行为也会随之改变。这就是状态模式的基本概念和应用。不过,要想深入理解和灵活运用状态模式,我们还需要了解其内部的结构和组成。

状态模式的结构和组成

在了解了状态模式的基本概念之后,我们来深入探讨一下它的结构和组成。状态模式主要由三个部分组成:上下文(Context)、抽象状态(Abstract State)和具体状态(Concrete State)。

首先,我们来看一下上下文。上下文是一个定义客户端所感兴趣的接口,并且维护一个具体状态类的实例,这个实例定义了当前的状态。上下文可以对外提供一种接口,用于改变它的状态。

然后,我们来看看抽象状态。抽象状态定义了一个接口,用于封装与上下文的一个特定状态相关的行为。在抽象状态中,我们可以定义一些方法,这些方法可以被不同的具体状态所重写,以实现不同状态下的行为。

最后,我们来看看具体状态。具体状态是抽象状态的子类,每一个子类实现了一个与上下文的状态相关的行为。在具体状态中,我们可以实现抽象状态中定义的方法,以实现不同状态下的行为。

下面是一个简单的Java代码示例,用于展示状态模式的结构和组成:

class Context {
    private AbstractState state;

    public void setState(AbstractState state) {
        this.state = state;
    }

    public void request() {
        state.handle(this);
    }
}

abstract class AbstractState {
    abstract void handle(Context context);
}

class ConcreteStateA extends AbstractState {
    void handle(Context context) {
        System.out.println("Handle in state A");
        context.setState(new ConcreteStateB());
    }
}

class ConcreteStateB extends AbstractState {
    void handle(Context context) {
        System.out.println("Handle in state B");
        context.setState(new ConcreteStateA());
    }
}

class OneMoreClass {
    public static void main(String[] args) {
        Context context = new Context();
        context.setState(new ConcreteStateA());
        context.request();
        context.request();
    }
}

在这个例子中,我们定义了一个名为OneMoreClass的类,用于展示状态模式的使用。在OneMoreClass类的main方法中,我们创建了一个Context对象,并通过setState方法设置了初始状态为ConcreteStateA,然后通过request方法触发状态转换。

contains
1
1
extends
extends
uses
Context
-AbstractState state
+setState(AbstractState state)
+request()
«abstract»
AbstractState
+handle(Context context)
ConcreteStateA
+handle(Context context)
ConcreteStateB
+handle(Context context)
OneMoreClass
+main(args)

通过这样的结构和组成,状态模式可以让我们的代码更加清晰,更加易于理解和维护。接下来,我们将通过一个互联网电子商务项目中的Java实例,进一步展示如何实现状态模式。

状态模式的Java实例

在前面,我们已经对状态模式的基本概念和结构有了一定的了解。现在,让我们通过一个具体的Java实例来看看如何在实际项目中实现状态模式。假设我们正在开发一个互联网电子商务项目,其中有一个Order订单类,订单的状态有多种,比如新订单、已支付、已发货等,每种状态下订单的行为也各不相同。

首先,我们需要定义一个上下文类,也就是订单类Order。这个类中维护了一个State状态对象,这个State对象定义了订单在当前状态下的行为。

public class Order {
    private State state;

    public void setState(State state) {
        this.state = state;
    }

    public void behavior() {
        this.state.behavior();
    }
}

接着,我们定义一个抽象状态类State,这个类定义了所有状态共有的行为接口。

public abstract class State {
    public abstract void behavior();
}

然后,我们根据订单的实际状态,定义出多个具体的状态类,比如NewOrderStatePaidStateDeliveredState等。这些类继承自State抽象状态类,并实现了behavior方法,定义了在该状态下订单的行为。

public class NewOrderState extends State {
    @Override
    public void behavior() {
        System.out.println("新订单,等待支付");
    }
}

public class PaidState extends State {
    @Override
    public void behavior() {
        System.out.println("已支付,等待发货");
    }
}

public class DeliveredState extends State {
    @Override
    public void behavior() {
        System.out.println("已发货,等待收货");
    }
}

这样,我们就实现了一个简单的状态模式。在实际的使用中,只需要改变Order订单对象的状态,就可以改变订单的行为。而且,如果需要增加新的状态,只需要增加新的状态类即可,无需修改Order类,符合开闭原则。

contains
1
1
extends
extends
extends
Order
-State state
+setState(State state)
+behavior()
«abstract»
State
+behavior()
NewOrderState
+behavior()
PaidState
+behavior()
DeliveredState
+behavior()

然而,虽然状态模式有许多优点,但也存在一些缺点,接下来我们将详细探讨状态模式的优缺点。

状态模式的优缺点

在前面,我们已经通过一个具体的Java例子详细地介绍了状态模式的实现过程,现在我们来讨论一下状态模式的优缺点,以及它在实际开发中的应用场景。

首先,让我们来看看状态模式的优点。一大优点就是它能够减少系统中的条件语句。在传统的程序设计中,我们通常会使用if-else或者switch-case语句来处理对象的状态转换,但这样做的问题是,随着状态的增多,条件语句也会越来越复杂,这对于代码的可读性和可维护性都是一种负面影响。而状态模式能够将每个状态的行为封装在一个类中,通过改变对象的状态来改变其行为,从而避免了复杂的条件语句。

其次,状态模式非常易于扩展。当我们需要添加一个新的状态时,只需要定义一个新的状态类即可,无需修改原有的代码,这符合了开闭原则。

然而,状态模式也有其缺点。那就是状态类的数量可能会过多,尤其是在状态非常复杂的情况下。每一个状态都对应一个状态类,这会导致系统中类的数量增多,增加了系统的复杂性。

至于状态模式的适用场景,一般来说,当一个对象的行为依赖于其状态,并且它需要在运行时刻改变其行为时,就可以考虑使用状态模式。例如,在电商平台中,订单的状态有多种,如待支付、已支付、待发货、已发货、已完成等,每种状态下订单的行为都是不同的,这就是一个典型的状态模式的应用场景。

总的来说,状态模式是一种非常实用的设计模式,它能够帮助我们更好地管理和控制对象的状态转换,提高代码的可读性和可维护性。但我们也要注意避免状态类的过度增多,使得系统过于复杂。

总结

在这个编程的海洋中,状态模式就像一艘小船,它能够根据风向(状态)改变航向(行为),让我们的代码更加清晰、易于理解和维护。它是我们处理复杂对象状态转换,减少条件语句的重要工具。但是,我们也要注意,每一个状态都对应一个状态类,这可能会导致状态类的数量过多,增加系统的复杂性。因此,我们在使用状态模式时,既要看到它的优点,也要注意它的缺点,恰如其分地使用,才能真正提高我们的代码质量。

在我们的编程生涯中,我们会遇到各种各样的设计模式,就像在海洋中遇到的各种各样的风向。有的风向会帮助我们顺利前行,有的风向则可能会让我们迷失方向。但无论如何,我们都要有勇气去面对,有智慧去选择,因为这就是编程,这就是我们的生活。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1529993.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Flink中任务(Tasks)和任务槽(Task Slots)详解

Flink中任务(Tasks)和任务槽(Task Slots)详解 任务槽(Task Slots) Flink中每一个worker(也就是TaskManager)都是一个JVM进程,它可以启动多个独立的线程,来并行执行多个子任务&#…

从零开始搭建游戏服务器 第四节 MongoDB引入并实现注册登录

这里写目录标题 前言正文添加依赖安装MongoDB添加MongoDB相关配置创建MongoContext类尝试初始化DB连接实现注册功能测试注册功能实现登录逻辑测试登录流程 结语下节预告 前言 游戏服务器中, 很重要的一点就是如何保存玩家的游戏数据. 当一个服务端架构趋于稳定且功能全面, 开发…

Spring单元测试+Mockito

一,背景 单元测试基本上是开发逃不过的一个工作内容,虽然往往因为过于无聊,或者过于麻烦,而停止于项目的迭代之中,不了了之了。其实不是开发们懒,而是上头要求的测试覆盖率高,但是又没有好用的…

zookeeper快速入门(合集)

zookeeper作为一个分布式协调框架,它的创建就是为了方便或者简化分布式应用的开发。除了服务注册与发现之外,它还能够提供更多的功能,但是对于入门来说,看这一篇就够了。后续会讲zookeeper的架构设计与原理,比如zookee…

MySQL 数据库设计范式

第一范式(1NF) 每一列都是不可分割的原子数据项第二范式(2NF) 在1NF的基础上,非码属性必须完全依赖于候选码(在1NF基础上消除非主属性对主码的部分函数依赖) 1.函数依赖A->B,如果通过A属性(属性组)的值…

[LeetBook]【学习日记】排序算法——归并排序

主要思想 归并排序是一种分治算法,其排序过程包括分和治分是指将要排序的序列一分为二、二分为四,直到单个序列中只有一个数治是指在分完后,将每两个元素重新组合,四合为二、二合为一,最终完成排序 图片作者&#xf…

python 实现把内层文件夹的文件,复制/剪切到外层文件夹

文章目录 如下图所示,收集了很多省市的文件,结果发现市一级的文件与区县一级的文件混在一起了。 接下来使用代码实现: 根据关键词识别出 市一级的文件;把市一级的文件,移动或者复制到省文件夹下;给出了py…

FPGA高端项目:FPGA基于GS2971+GS2972架构的SDI视频收发+GTX 8b/10b编解码SFP光口传输,提供2套工程源码和技术支持

目录 1、前言免责声明 2、相关方案推荐本博主所有FPGA工程项目-->汇总目录本博已有的 SDI 编解码方案本方案的SDI接收发送本方案的SDI接收图像缩放应用本方案的SDI接收纯verilog图像缩放纯verilog多路视频拼接应用本方案的SDI接收HLS图像缩放HLS多路视频拼接应用本方案的SDI…

前端静态开发案例-基于H5C3开发的仿照视频网站的前端静态页面-2 样式表部分和效果展示

原创作者:田超凡(程序员田宝宝) 版权所有,引用请注明原作者,严禁复制转载 charset "utf-8"; /* 程序员田宝宝原创版权所有,仿冒必究,该界面是仿照某视频网站官网开发的静态页面 */ …

【Thread 线程】线程的方法与状态

SueWakeup 个人中心:SueWakeup 系列专栏:学习Java 个性签名:保留赤子之心也许是种幸运吧 本文封面由 凯楠📷 友情赞助播出! 目录 一个线程的生命周期 线程终止的原因 线程的方法 Thread 类的静态方法 1. 设置线程…

linux单机部署hadoop

1.下载安装包 https://archive.apache.org/dist/hadoop/common/ 2.上传压缩 3.修改配置文件 1)设置JDK的路径 cd /usr/local/software/hadoop-3.1.3/etc/hadoop vi hadoop-env.sh export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.402.b06-1.el7_9.x86_64/ 查看…

【数据结构和算法初阶(C语言)】二叉树的顺序结构--堆的实现/堆排序/topk问题详解---二叉树学习日记②1

目录 ​编辑 1.二叉树的顺序结构及实现 1.1 二叉树的顺序结构 2 堆的概念及结构 3 堆的实现 3.1堆的代码定义 3.2堆插入数据 3.3打印堆数据 3.4堆的数据的删除 3.5获取根部数据 3.6判断堆是否为空 3.7 堆的销毁 4.建堆以及堆排序 4.1堆排序---是一种选择排序 4.2升序建大堆&a…

微信小程序 canvas层级过高覆盖原生组件

一、背景 微信小程序中使用signature第三方插件完成签名效果&#xff0c;但真机调试时发现canvas层级过高遮挡了按钮 二、具体问题 问题原因&#xff1a;签名后点击按钮无法生效 问题代码&#xff1a; <template><view class"sign_page" v-cloak>&l…

nodejs基于vue超市信息管理系统flask-django-php

互联网的快速发展&#xff0c;使世界各地的各种组织的管理方式发生了根本性的变化&#xff0c;我国政府、企业等组织在上个世纪90年代就已开始考虑使用互联网来管理信息。由于以前的种种因素&#xff0c;比如网络的普及率不高&#xff0c;用户对它的认知度不够&#xff0c;以及…

计算机网络:数据交换方式

计算机网络&#xff1a;数据交换方式 电路交换分组交换报文交换传输对比 本博客介绍计算机之间数据交换的三种方式&#xff0c;分别是电路交换、分组交换以及报文交换。 电路交换 我们首先来看电路交换&#xff0c;在电话问世后不久&#xff0c;人们就发现要让所有的电话机都…

基于Spring Boot网络相册设计与实现

摘 要 网络相册设计与实现的目的是让使用者可以更方便的将人、设备和场景更立体的连接在一起。能让用户以更科幻的方式使用产品&#xff0c;体验高科技时代带给人们的方便&#xff0c;同时也能让用户体会到与以往常规产品不同的体验风格。 与安卓&#xff0c;iOS相比较起来&am…

【OCR】OCR开源文字识别工具

在日常的工作中&#xff0c;例如自动化测试开展时&#xff0c;经常涉及到一些验证码识别、文本识别、图像识别的场景&#xff0c;市面上虽也有很多识别工具&#xff0c;但质量、准确性参差不齐。 今天给大家推荐一个开源OCR项目:Umi-OCR&#xff0c;功能很强大&#xff0c;而且…

jquery 列表框可以手动修改(调用接口修改)

类似于这种 直接上代码 列表框 <td>//目的主要是获取属性名的(要更改的属性名) 在下面juqery的这一行(var field $(thisobj).prev(input).attr(name);)有体现<input type"hidden" name"voyage" value"${M_PSI_PERIOD_INFO.port}">…

Vulnhub - Hacker_Kid

希望和各位大佬一起学习&#xff0c;如果文章内容有错请多多指正&#xff0c;谢谢&#xff01; 个人博客链接&#xff1a;CH4SER的个人BLOG – Welcome To Ch4sers Blog Hacker_Kid 靶机下载地址&#xff1a;https://www.vulnhub.com/entry/hacker-kid-101,719/ WP 参考&…

路由器里如何设置端口映射?

在互联网时代&#xff0c;我们经常需要将内部网络的服务暴露到公网以便其他人访问。直接将内部网络暴露在公网上存在一定的安全风险。为了解决这个问题&#xff0c;我们可以利用路由器里设置端口映射来实现将特定端口的访问请求转发到内部网络的特定设备上。 端口映射的原理 端…