热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

初识设计模式–状态模式

简介状态模式(StateDesignPattern)的定义是,允许一个对象在内部状态改变时改变它的行为,对象看起来似乎修改了它的类。在状态模式中,通常有两种方式实现状态转换:统一由

简介

状态模式(State Design Pattern)的定义是,允许一个对象在内部状态改变时改变它的行为,对象看起来似乎修改了它的类。

在状态模式中,通常有两种方式实现状态转换:统一由环境类来负责状态之间的转换;由具体状态类来负责状态之间的转换。


状态机


概念

状态模式一般用于实现状态机,而状态机常用在游戏、工作流引擎等系统开发中。状态机的实现方式有多种,除了状态模式,比较常用的还有分支逻辑法和查表法。

状态机会有 3 个组成部分:状态(State)、事件(Event)、动作(Action)。

拿“超级马里奥”游戏来举例,其中马里奥形态的转变就是一个状态机:初始状态是小马里奥,吃蘑菇这个事件会触发状态的转移,从小马里奥转变成超级马里奥,以及触发动作的执行(增加积分)。


分支逻辑法

最简单的状态机实现方式就是分支逻辑法,其理解非常简单,就是将每一个状态转移都直译成代码。

其缺点是,代码中会充斥着 if-else 或 switch 分支判断逻辑,甚至是嵌套的分支判断逻辑,当状态较多时,代码的可读性会比较低。


查表法

查表法的实现逻辑是,将状态、事件和动作三者存储到一个二维表中,这样可以清晰地表示,一个动作发生某个事件时,会转移到怎样的状态以及触发怎样的动作。

状态机查表法二维表

在实现过程中,将二维表的数据存储到配置文件中,可以通过动态地修改配置文件以达到修改状态机的目的。


具体实现

仍然还是拿“超级马里奥”游戏来举例说明,初始状态是小马里奥,吃蘑菇这个事件会触发状态的转移,从小马里奥转变成超级马里奥,以及触发动作的执行(增加积分)。

首先,定义一个抽象状态 State 接口,其代码示例如下:

public interface State {
// 声明抽象业务方法,不同的具体状态可以有不同的方法实现
void handle();
}

对于小马里奥状态,定义一个实现 State 接口的 SmallState 类,其代码示例如下:

public class SmallState implements State {
@Override
public void handle() {
// 业务方法的具体实现
System.out.println("变成小马里奥状态");
}
}

对于超级马里奥状态,定义一个实现 State 接口的 SuperState 类,其代码示例如下:

public class LargeState implements State {
@Override
public void handle() {
// 业务方法的具体实现
System.out.println("变成超级马里奥状态");
}
}

在状态模式中,需要创建一个 Context 类用于保存对于一个具体状态对象的引用,并且负责状态的保持和转变。其代码示例如下:

public class Context {
private State state;
public void setState(State state) {
// 注入状态对象
this.state = state;
}
public void request() {
// 调用状态对象的业务方法
this.state.handle();
}
}

对于客户端,直接操作 Context 对象并根据状态的转变传入不同的状态对象,这样即可实现状态机的功能,其代码示例如下:

class StateDemo {
public static void main(String[] args) {
Context cOntext= new Context();
State smallState = new SmallState();
context.setState(smallState);
// 变成小马里奥状态
context.request();
State largeState = new LargeState();
context.setState(largeState);
// 变成超级马里奥状态
context.request();
}
}

总结


优点

状态模式的主要优点如下:



  • 状态模式统一封装了状态的转换规则,对状态转换代码进行集中管理

  • 将不同的状态引入独立的对象中使得状态转换变得更加明确,且减少对象间的相互依赖

  • 状态的职责分明,通过定义新的子类可以很容易地增加新的状态和转换


缺点

状态模式的主要缺点如下:



  • 每个状态都会新增一个具体的状态子类,导致系统的运行开销增大

  • 状态模式的结构和实现都较为复杂,使用不当会导致程序结构和代码的混乱

  • 对于可以切换的状态模式,增加新的状态类需要修改那些负责状态转换的源码,否则无法切换到新增的状态,而且修改某个状态类的行为也要修改对应类的源码


适用场景

状态模式的适用场景如下:



  • 对象的行为依赖于它的状态,状态的改变将导致行为的变化

  • 在代码中包括大量与对象状态有关的条件语句

首发于翔仔的个人博客,点击查看更多。



推荐阅读
  • 使用EF Core在.Net Core控制台应用中操作SQLite数据库
    本文介绍如何利用Visual Studio 2019和Windows 10环境,通过Entity Framework Core(EF Core)实现对SQLite数据库的读写操作。项目源代码可从百度网盘下载。 ... [详细]
  • 本文介绍如何使用Java实现AC自动机(Aho-Corasick算法),以实现高效的多模式字符串匹配。文章涵盖了Trie树和KMP算法的基础知识,并提供了一个详细的代码示例,包括构建Trie树、设置失败指针以及执行搜索的过程。 ... [详细]
  • C#爬虫Fiddler插件开发自动生成代码
    哈喽^_^一般我们在编写网页爬虫的时候经常会使用到Fiddler这个工具来分析http包,而且通常并不是分析一个包就够了的,所以为了把更多的时间放在分析http包上,自动化生成 ... [详细]
  • 在现代移动应用开发中,尤其是iOS应用,处理来自服务器的JSON数据是一项基本技能。无论是使用Swift还是PHP,有效地解析和利用JSON数据对于提升用户体验至关重要。本文将探讨如何在Swift中优雅地处理JSON,以及PHP中处理JSON的一些技巧。 ... [详细]
  • PHP 5.4.8 编译安装指南
    本文详细介绍了如何在Linux环境下编译安装PHP 5.4.8,并配置为FastCGI模式运行。包括所需依赖包的安装、源代码下载、编译配置及启动服务等步骤。 ... [详细]
  • 拖拉切割直线 ... [详细]
  • 深入解析Spring Boot项目的启动机制
    在Java后端开发中,Spring Boot框架以其简洁性和强大的功能受到了广泛欢迎。本文将探讨Spring Boot项目启动的核心——SpringApplication类及其run()方法的工作原理。 ... [详细]
  • 本文讨论了在处理分页数据时常见的低级错误,并提供了优化后的代码示例,以减少重复代码并提高可读性和维护性。 ... [详细]
  • 第三周课堂测试1、使用汇编语言编写指令时,用一些简单的容易记忆的符号来代替二进制指令,比机器语言更为方便,属于高级语言。(B ... [详细]
  • Java 中静态和非静态嵌套类的区别 ... [详细]
  • Qt应用开发:创建基本窗口
    本文介绍如何使用Qt框架创建基础窗口的两种方法。第一种方法直接在main函数中创建并显示窗口;第二种方法通过定义一个继承自QWidget的类来实现更复杂的功能。 ... [详细]
  • 本文探讨了Lua中元表和元方法的使用,通过具体的代码示例展示了如何利用这些特性来实现类似C语言中的运算符重载功能。 ... [详细]
  • 本文介绍了DOM中用于获取节点信息的关键属性,包括父节点、子节点列表、首个及末个子节点、相邻兄弟节点以及节点类型等,同时提供了每个属性的具体使用说明。 ... [详细]
  • 本文探讨了Flutter和Angular这两个流行框架的主要区别,包括它们的设计理念、适用场景及技术实现。 ... [详细]
  • APOC 函数详解:路径查询方法
    本文将深入探讨 APOC 库中的路径查询功能,特别是如何利用 `apoc.path.expand` 函数实现灵活的路径查询,包括动态设置最大路径长度等高级特性。 ... [详细]
author-avatar
嗷唔喵_105
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有