Java设计模式之状态模式

2023-10-27

本文继续介绍23种设计模式系列之策略模式。

何时使用
State模式在实际使用中比较多,适合“状态”的切换。因为我们经常会使用If else if else 进行状态切换,如果针对状态的这样判断切换反复出现,我们就要联想到是否可以采取State模式了。
这里要阐述的是”开关切换状态” 和” 一般的状态判断”是有一些区别的,” 一般的状态判断”也是有 if..elseif结构,例如:


if (which==1) state="hello";
else if (which==2) state="hi";
else if (which==3) state="bye";

这是一个 ” 一般的状态判断”,state值的不同是根据which变量来决定的,which和state没有关系.如果改成:


if (state.euqals("bye")) state="hello";
else if (state.euqals("hello")) state="hi";
else if (state.euqals("hi")) state="bye";

这就是 “开关切换状态”,是将state的状态从”hello”切换到”hi”,再切换到””bye”,在切换到”hello”,好象一个旋转开关,这种状态改变就可以使用State模式了。
如果单纯有上面一种将”hello”–>”hi”–>”bye”–>”hello”这一个方向切换,也不一定需要使用State模式,因为State模式会建立很多子类,复杂化,但是如果又发生另外一个行为:将上面的切换方向反过来切换,或者需要任意切换,就需要State了。

下面是一个一般写法的状态切换

public class Context{
  private Color state=null;
  public void push(){
    //如果当前red状态,切换到blue
    if (state==Color.red) state=Color.blue;
    //如果当前blue状态,切换到green
    else if (state==Color.blue) state=Color.green;
    //如果当前black状态,切换到red
    else if (state==Color.black) state=Color.red;
    //如果当前green状态,切换到black
    else if (state==Color.green) state=Color.black;
    Sample sample=new Sample(state);
    sample.operate();
  }

  public void pull(){
    //与push状态切换正好相反
    if (state==Color.green) state=Color.blue;
    else if (state==Color.black) state=Color.green;
    else if (state==Color.blue) state=Color.red;
    else if (state==Color.red) state=Color.black;
    Sample2 sample2=new Sample2(state);
    sample2.operate();
  }
}

使用策略模式重写上面例子
State需要两种类型实体参与:
1.state manager 状态管理器 ,就是开关 ,如上面例子的Context实际就是一个state manager, 在state manager中有对状态的切换动作.
2.用抽象类或接口实现的父类,,不同状态就是继承这个父类的不同子类.

首先建立一个父类


public abstract class State{
  public abstract void handlepush(Context c);
  public abstract void handlepull(Context c);
  public abstract void getcolor();
}

public class BlueState extends State{

  public void handlepush(Context c){
        System.out.println(“变成绿色");
     c.setState(new GreenState());
  }

  public void handlepull(Context c){
       System.out.println(“变成红色");
    c.setState(new RedState());
  }

  public abstract void getcolor(){
       return (Color.blue);
   }
}

public class GreenState extends State{

  public void handlepush(Context c){
        System.out.println(“变成黑色");
     c.setState(new BlackState());
  }

  public void handlepull(Context c){
        System.out.println(“变成蓝色");
     c.setState(new BlueState());
  }

  public abstract void getcolor(){
        return (Color.green);
    }
}

public class BlackState extends State{

  public void handlepush(Context c){
        System.out.println(“变成红色");
     c.setState(new RedState());
  }

  public void handlepull(Context c){
       System.out.println(“变成红色");
    c.setState(new RedState());
  }

  public abstract void getcolor(){
        return (Color.black);
   }
}

public class RedState extends State{

  public void handlepush(Context c){
       System.out.println(“变成蓝色");
     c.setState(new BlueState());
  }

  public void handlepull(Context c){
       System.out.println(“变成黑色");
    c.setState(new BlackState());
  }

  public abstract void getcolor(){
       return (Color.red);
    }
}

重新改写State manager 也就是本例的Context


public class Context{

  private Sate state=null; //我们将原来的 Color state 改成了新建的State state;

  //setState是用来改变state的状态 使用setState实现状态的切换
  pulic void setState(State state){
    this.state=state;
  }

  public void push(){
    //状态的切换的细节部分,在本例中是颜色的变化,已经封装在子类的handlepush中实现,这里无需关心
    state.handlepush(this);
    //假设sample要使用state中的一个切换结果,使用getColor()
    Sample sample=new Sample(state.getColor());
    sample.operate();
  }

  public void pull(){
    state.handlepull(this);
       //假设sample要使用state中的一个切换结果,使用getColor()
    Sample2 sample2=new Sample2(state.getColor());
    sample2.operate();
  }
}

状态模式在工作流或游戏等各种系统中有大量使用,甚至是这些系统的核心功能设计,例如ERP系统中,一个批文的状态有多种:未办;正在办理;正在批示;正在审核;已经完成等各种状态,使用状态机可以封装这个状态的变化规则,从而达到扩充状态时,不必涉及到状态的使用者。

总结
使用状态模式前,客户端外界需要介入改变状态,而状态改变的实现是琐碎或复杂的。
使用状态模式后,客户端外界可以直接使用事件Event实现,根本不必关心该事件导致如何状态变化,这些是由状态机等内部实现。
这是一种Event-condition-State,状态模式封装了condition-State部分。
每个状态形成一个子类,每个状态只关心它的下一个可能状态,从而无形中形成了状态转换的规则。如果新的状态加入,只涉及它的前一个状态修改和定义。

状态模式的主要优点在于封装了转换规则,并枚举可能的状态,它将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为,还可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数;其缺点在于使用状态模式会增加系统类和对象的个数,且状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱,对于可以切换状态的状态模式不满足“开闭原则”的要求。

更多设计模式:23种设计模式系列

作者:jason0539

博客:http://blog.csdn.net/jason0539(转载请说明出处)

欢迎关注,更多福利

这里写图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java设计模式之状态模式 的相关文章

  • 使用 POST 将数据从 Android 发送到 AppEngine Datastore

    抱歉 如果这是一个简单的问题 但我只是不知道我应该做什么 而且我认为我有点超出了我的深度 我想将数据从 Android 应用程序发送到在 Google App Engine 上运行的应用程序 数据必须从那里写入数据存储区 我的数据主要采用对
  • Grizzly 和 Servlet 容器上下文

    我试图在我编写的 在 Grizzly 上运行的 Servlet 中获取一些注入的上下文 例如 Session 或 HttpServletRequest 但我所做的似乎都不起作用 整个过程似乎过早地停止了 并出现以下错误 SEVERE Mis
  • 是否可以使用检测重新定义核心 JDK 类?

    我想重新定义字节码StackOverflowError构造函数 因此当堆栈溢出发生时我有一个 钩子 我想要做的就是在构造函数的开头插入对我选择的静态方法的单个方法调用 是否有可能做到这一点 您应该能够使用两种方法之一来完成此操作 除非在过去
  • Java 的 System.arraycopy() 对于小数组有效吗?

    是Java的System arraycopy 对于小数组来说是高效的 或者它是本机方法这一事实是否使其可能比简单的循环和函数调用效率低得多 本机方法是否会因跨越某种 Java 系统桥梁而产生额外的性能开销 稍微扩展一下 Sid 所写的内容
  • JPA 为每个项目选择最新实例

    假设我有一个会议实体 每次会议都有一个与会者和一个会议日期 在我的会议表中 我可能为每个与会者举行多个会议 每个会议都有不同的日期 我需要一个 JPA 查询 该查询将为所有与会者仅选择最新的会议 例如 如果我的桌子看起来像这样 Meetin
  • 将位于 jar 中的文件读取为 java.io.File 对象

    与此类似的问题已发布 但似乎没有一个答案对我的情况有帮助 我正在编写一个程序包 它使用 Google 的凭据来获取 Google Apps 用户 为此 我使用服务帐户 因此为了检索凭据 我需要提供 除其他外 一个 p12 签名文件 Cred
  • 如何使用 JAVA 和 ADB 命令检查 Appium 中键盘是否打开

    我正在尝试检查 Android 默认键盘是否打开 我没有找到任何可以在 Appium 中使用 JAVA 和 ADB 命令检查键盘的内容 我发现这个 ADB 命令可以检查键盘是否打开 adb shell dumpsys input metho
  • java中main的返回类型

    我想知道为什么java中main方法只有void返回类型 public static void main String args 为什么main方法除了void之外没有其他返回类型 Thanks 简短的回答是 因为这就是语言规范 http
  • 如何加快 jar 签名者的速度?

    我使用 ant 来签署我的 jars 以进行网络启动部署 Ant signjar 在 Web 启动签名时非常慢 如何加快签名过程 我找到了一种可能的解决方案 早些时候 在构建脚本 ant signjar 中 按顺序调用所有 jar 我们使用
  • 使用 eclipse 配置mockito 时出现问题。给出错误:java.lang.verifyError

    当我将我的mockito库添加到类路径中 并使用一个简单的mockito示例进行测试时 我尝试使用模拟对象为函数add返回错误的值 我得到java lang verifyerror 以下是用于测试的代码 后面是 logcat Test pu
  • 在 IntelliJ 中创建可执行 JAR(Java 18、JavaFX 18 Maven 项目),“警告:不支持的 JavaFX 配置...”

    我有一个 Java 18 JavaFX 18 Maven 项目 除了 javaFX 库之外 它还有很多库需要包含在工件中 我想创建一个工件 一个 jar 其中包含所有依赖项 我开始按照这个视频来创建 jar https www youtub
  • 在Java程序中计算zip文件的md5哈希值

    我有一个 zip 文件 在我的 Java 代码中我想计算 zip 文件的 md5 哈希值 有没有我可以用于此目的的 java 库 一些例子将非常感激 谢谢 几周前我通过这篇文章做到了这一点 http www javalobby org ja
  • Java 8 Stream - 为什么过滤器方法不执行? [复制]

    这个问题在这里已经有答案了 我正在学习使用java流进行过滤 但是过滤后的流没有打印任何内容 我认为过滤器方法没有被执行 我的过滤代码如下 Stream of d2 a2 b1 b3 c filter s gt s startsWith b
  • Jar Manifest 文件的使用混乱

    我正在阅读使用 jar 工具打包 java 应用程序 我注意到 META INF 目录下创建了一个清单文件 对于一个简单的应用程序来说 感觉它没有任何作用 我在 stackoverflow 上搜索以了解 Manifest 文件的用法 我碰到
  • servlet 如何获取 servlet 之外的文件的绝对路径?

    我们一直在使用 System getProperties user dir 来获取属性文件的位置 现在它已经部署在 Tomcat 上 通过 servlet 系统调用将位置指定为 tomcat 而不是属性文件所在的位置 我们如何动态调用属性文
  • Java 中的可迭代求和?

    有没有一个库可以做到这一点 public class Iterables private Iterables public static
  • 如何在jpa中共享EntityManagerFactory

    我是 jpa 的新手 这是场景 我正在开发一个 Web 应用程序 其中 多个用户可以登录 当 user1 注销时 我正在使用下面的代码 public static void closeEntityManagerFactory if enti
  • 使用 Tomcat 和 gradle 进行休眠

    免责声明 我是 Java 新手 我正在尝试使用 Tomcat 和 Gradle 设置 Hibernate 构建运行正确 但看起来像persistence xml文件未被读取 我的项目结构如下 build gradle src main ja
  • 如何使用 AEM 解析 org.apache.http.ssl?

    最终 我尝试在 Java 代码中使用 AWS S3 库来通过 AEM 启用服务器端 S3 上传 但在安装依赖项和 或由 AEM 识别时遇到了问题 每次我添加新的依赖项时 都会弹出五个问题 在我尝试构建的这个包中 这是我看到的错误 The i
  • 用于从链表中删除元素的大 O 表示法[重复]

    这个问题在这里已经有答案了 我正在阅读有关链接列表的内容 我发现 从链表中删除所需的元素需要 O n 运行时间 其中 n 是元素的数量 列表中的元素 http www cs mcgill ca dprecup courses IntroCS

随机推荐

  • 使用代码来使用 JS 的 download 库来下载资源

    如题 用以下代码来使用 JS 的 download 库来下载资源 引入 download 库 import download from downloadjs 要下载的文件的 URL 和文件名 const fileUrl https exam
  • unable to boot the simulator,无法启动模拟器已解决

    我在百度上所搜的都是以前的老方法 新版的Mac已经没有Recovery了 因此我只好去bing上查找资料 方法很简单 用Mac安装镜像进入Recovery模式 然后输入 csrutil disable 就行了 剩下的和原来的方法一致
  • 浮点数和整数之间的转换

    当一个整数int i 12345被强制转换为一个FLOAT型变量 float f float i 假设sizeof int 32 float为单精度 sizeof float 32 那么i 12345 十进制 000000000000000
  • UE4_聚合图

    UE4 聚合图
  • 【Python 1-0】10个学习Python的理由以及Python的优势有哪些?

    Python的由来 首发地址 Python的创始人是吉多 范罗苏姆 1989年他在阿姆斯特丹的CWI工作 圣诞节期间 吉多 范罗苏姆为了打发圣诞节的无聊 决定开发一个新的脚本解释程序 作为ABC 语言的一种继承 之所以选择Python作为编
  • Maven覆盖私服上的jar包,本地仓库无法更新的问题

    在上传第三方jar包到私服环境时 第一次上传成功后 突然发现上传的jar包有问题 但是因为已经指定了版本号 并且是release版本的jar包 因为不想更换版本号 所以再重复上传正确的jar包 就会出现如下错误 一种解决办法是指定另外一个版
  • Gitflow工作流程

    在工作场合实施Git的时候 有很多种工作流程可供选择 此时反而会让你手足无措 本文罗列了企业团队最常用的一些Git工作流程 包括Centralized Workflow Feature Branch Workflow Gitflow Wor
  • Container命令ctr,crictl的用法

    Container命令ctr crictl的用法 版本 ctr containerd io 1 4 3 containerd 相比于docker 多了namespace概念 每个image和container 都会在各自的namespace
  • 通过Vue.js的axios请求WFS数据并处理请求回来的XML文件

    前端小白的第一个博客 前言 这个是在GIS开发过程中遇到的一个小问题 因为里面包含了蛮多的知识点 故将其记录 废话不多说进入正文 正文 此次需要解决的问题是通过wfs接口来获取到一些需要的内容 然后以这些内容为基础进行一系列的操作 以下展示
  • 1.3远程控制及文件传输

    我们经常用的是Windows操作系统 又经常需要与Ubuntu进行文件传输 同时为了能在Windows上操作我们的Ubuntu 这里推荐一个文件传输和一个远程控制的程序 文件传输WinSCP 官方下载地址 https sourceforge
  • VsCode官网快速下载

    VsCode官网 以Win10下载为例 问题描述 下载时 发现速度很慢 甚至会没有下载速度 如下图 解决方法 右键复制这个下载链接 将其前半部分修改为vscode cdn azure cn 例如 原下载链接 https az764295 v
  • Codeforces 600C Make Palindrome 【贪心 找字典序最小回文串】

    一 题目概述 C Make Palindrome time limit per test 2 seconds memory limit per test 256 megabytes input standard input
  • 如何在Anaconda安装opencv,下面分享一下教程

    1 首先下载opencv安装包 下载地址 https download csdn net download qq 42375391 12333992 2 安装完成后 在Anaconda Prompt内使用pip install完整路径文件名
  • 算法:模拟思想算法

    文章目录 实现原理 算法思路 典型例题 替换所有问号 提莫攻击 N字型变换 外观序列 总结 本篇总结的是模拟算法 实现原理 模拟算法的实现原理很简单 就是依据题意实现题意的目的即可 考察的是你能不能实现题目题意的代码能力 算法思路 没有很明
  • openwrt 自动签到插件-食用指南

    目录 openwrt 自动签到插件下载 openwrt 插件安装需要的依赖 openwrt 插件安装 文件上传 openwrt 自动签到配置 设置详情 Cookie获取失败 解决方法 Charles 抓包获取Cookie openwrt 配
  • 计算机设备问题代码43,双击unknown device由于该设备有问题Windows已将其停止(代码 43)怎么办解决教程...

    金士顿U盘做的启动盘 8G 在别人的电脑上储存文件正常 但在自己的电脑上无法识别 在设备管理器中显示黄色叹号 属性显示 该设备存在问 题 windows已将其停止 代码43 本机win7系统 别人电脑为XP系统 已将 禁用 注册表 dos设
  • Linux 阻塞IO(等待队列)原理及架构

    一 阻塞操作 阻塞操作是指在执行折本操作时 若不能获得自愿 则挂起进程直到满足可操作性的条件后在进行操作 被挂起的进程进入休眠状态 被从调度器的运行队列移走 直到等待的条件被满足 假设recvfrom函数是一个系统调用 阻塞不是低效率 如果
  • vue -- 验证码

  • 25-python函数(低阶)

    一 函数的作用 函数的本质就是将一段具有独立功能的代码块整合到一个整体并命名 在需要的时候通过调用函数名完成某种需求 以提高代码的利用率 从而在稳定系统的同时减轻程序员的工作 二 函数的使用过程 函数使用分为两个步骤 先定义 后调用 定义函
  • Java设计模式之状态模式

    本文继续介绍23种设计模式系列之策略模式 何时使用 State模式在实际使用中比较多 适合 状态 的切换 因为我们经常会使用If else if else 进行状态切换 如果针对状态的这样判断切换反复出现 我们就要联想到是否可以采取Stat