首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

设计模式之状态模式(三分钟学会一个设计模式)

编程知识
2024年09月12日 09:23

状态模式(State Pattern)的定义是这样的:类的行为是基于它的状态改变的。
注意这里的状态不是狭义的指对象维护了一个“状态”字段,我们传入了不同的枚举值,对象整体的表现行为(对外方法)就改变了。
而是指内部的(任意)字段如果发生了变化,那么它的状态就变了,那么它对外的表现形式就变了。
它是面向对象的23种设计模式中的一种,属于行为模式的范围。
通常我们在解决不同状态下,对外方法的不同表现时,可以定义若干的枚举,然后写一大堆if、 elseif、 switch等选择命令来区分不同的状态,然后走不同的业务分支。
而状态模式是支持将这些分支业务抽离出一个独立类(状态类),我们通过传入不同的状态类,就可以动态的执行不同的业务方法。
整体的结构大概是这样的:

业务类维护了一个内部状态对象,这个状态对象支持由外部传入,切换为不同的状态对象。
而这些状态对象都统一实现了具体的方法,业务类内部在执行业务方法时,会调用这些状态对象中实现的方法。(防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )这样在切换状态时,业务方法就会调用不同的状态对象的方法了。从面向对象的角度,实现了状态变化,类行为的同步变化。
来看一个具体的代码示例:

枚举类

1 package com.example.demo.learn.pattern.behavior.status;
2 
3 public enum TextStatusEnum {
4     ONLY_READ,
5     READ_WRITE,
6     UNAVAILABLE;
7 
8 }

状态定义接口

 1 package com.example.demo.learn.pattern.behavior.status;
 2 
 3 /**
 4  * @discription
 5  */
 6 public interface TextState {
 7      TextStatusEnum getStatus();
 8 
 9      void write(String content);
10 
11      void clear();
12 
13      String read();
14 
15      void setContent(StringBuilder sb);
16 }

只读状态

 1 package com.example.demo.learn.pattern.behavior.status;
 2 
 3 import lombok.Data;
 4 import lombok.extern.slf4j.Slf4j;
 5 
 6 /**
 7  * @discription
 8  */
 9 @Slf4j
10 @Data
11 public class OnlyReadState implements TextState {
12     private static final TextStatusEnum textStatus = TextStatusEnum.ONLY_READ;
13 
14     private StringBuilder sb;
15 
16     @Override
17     public TextStatusEnum getStatus() {
18         return textStatus;
19     }
20 
21     public void write(String content) {
22         log.error("sorry, you can not write");
23     }
24 
25     public void clear() {
26         log.error("sorry, you can not clear");
27     }
28 
29     public String read() {
30         return sb.toString();
31     }
32 
33     @Override
34     public void setContent(StringBuilder sb) {
35         this.sb = sb;
36     }
37 }

读写状态

 1 package com.example.demo.learn.pattern.behavior.status;
 2 
 3 import lombok.Data;
 4 import lombok.extern.slf4j.Slf4j;
 5 
 6 /**
 7  * @discription
 8  */
 9 @Data
10 @Slf4j
11 public class ReadWriteState implements TextState {
12     private static final TextStatusEnum textStatus = TextStatusEnum.ONLY_READ;
13 
14     private StringBuilder sb = new StringBuilder();
15 
16     @Override
17     public TextStatusEnum getStatus() {
18         return textStatus;
19     }
20 
21     public void write(String content) {
22         sb.append(content);
23     }
24 
25     public void clear() {
26         sb.setLength(0);
27     }
28 
29     public String read() {
30         return sb.toString();
31     }
32 
33     @Override
34     public void setContent(StringBuilder sb) {
35         this.sb = sb;
36     }
37 }

本文编辑器(业务类/上下文)

 1 package com.example.demo.learn.pattern.behavior.status;
 2 
 3 import lombok.Data;
 4 import lombok.extern.slf4j.Slf4j;
 5 
 6 /**
 7  * @discription
 8  */
 9 @Slf4j
10 public class TextEditor {
11 
12     private StringBuilder sb = new StringBuilder();
13 
14     private TextState textState;
15 
16     public void setState(TextState textState) {
17         textState.setContent(sb);
18         this.textState = textState;
19     }
20 
21     public void write(String content) {
22         if (textState == null) {
23             log.error("no state exist");
24             return;
25         }
26         textState.write(content);
27     }
28 
29     public void clear() {
30         if (textState == null) {
31             log.error("no state exist");
32             return;
33         }
34         textState.clear();
35     }
36 
37     public String read() {
38         if (textState == null) {
39             log.error("no state exist");
40             return "no state";
41         }
42         return textState.read();
43     }
44 
45 }

主类

 1 package com.example.demo.learn.pattern.behavior.status;
 2 
 3 import lombok.extern.slf4j.Slf4j;
 4 
 5 /**
 6  * @discription
 7  */
 8 @Slf4j
 9 public class PatternMain {
10     public static void main(String[] args) {
11         TextEditor editor = new TextEditor();
12         String text;
13 
14         //可读写状态
15         TextState rw = new ReadWriteState();
16         editor.setState(rw);
17         for (int i = 0; i < 3; i++) {
18             editor.write("write" + i);
19             text = editor.read();
20             log.warn("read :" + text);
21         }
22         editor.clear();
23         text = editor.read();
24         log.warn("after clear, we read :" + text);
25         editor.write("last write");
26 
27         log.warn("-----------------------now, we exchange state to only read-----------------------" );
28         //只读状态
29         TextState or = new OnlyReadState();
30         editor.setState(or);
31         for (int i = 0; i < 3; i++) {
32             editor.write("write" + i);
33             text = editor.read();
34             log.warn("read :" + text);
35         }
36         editor.clear();
37         text = editor.read();
38         log.warn("after clear, we read :" + text);
39     }
40 }

输出效果如下:

10:02:52.356 [main] WARN com.example.demo.learn.pattern.behavior.status.PatternMain - read :write0
10:02:52.368 [main] WARN com.example.demo.learn.pattern.behavior.status.PatternMain - read :write0write1
10:02:52.369 [main] WARN com.example.demo.learn.pattern.behavior.status.PatternMain - read :write0write1write2
10:02:52.371 [main] WARN com.example.demo.learn.pattern.behavior.status.PatternMain - after clear, we read :(防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )
10:02:52.372 [main] WARN com.example.demo.learn.pattern.behavior.status.PatternMain - -----------------------now, we exchange state to only read-----------------------
10:02:52.376 [main] ERROR com.example.demo.learn.pattern.behavior.status.OnlyReadState - sorry, you can not write
10:02:52.378 [main] WARN com.example.demo.learn.pattern.behavior.status.PatternMain - read :last write
10:02:52.378 [main] ERROR com.example.demo.learn.pattern.behavior.status.OnlyReadState - sorry, you can not write
10:02:52.378 [main] WARN com.example.demo.learn.pattern.behavior.status.PatternMain - read :last write
10:02:52.379 [main] ERROR com.example.demo.learn.pattern.behavior.status.OnlyReadState - sorry, you can not write
10:02:52.379 [main] WARN com.example.demo.learn.pattern.behavior.status.PatternMain - read :last write
10:02:52.379 [main] ERROR com.example.demo.learn.pattern.behavior.status.OnlyReadState - sorry, you can not clear
10:02:52.380 [main] WARN com.example.demo.learn.pattern.behavior.status.PatternMain - after clear, we read :last write

Process finished with exit code 0

我们可以看到在最初设置读写状态后,可以做读、写、清除等操作

在设置读状态后则只能读了。

这样回头来看,其实我们就是将不同if Switch的选择分支,连同选择的状态,一同封装到不同的状态类中,我们需要新增一种分支逻辑,不再需要修改选择分支,而是只需要新增一个状态类即可。
那是否状态模式可以替代传统的if 选择分支,答案是不能,本质上还是一个度的原因,面相对象如果过度设计,会导致类的数量无限膨胀,难以维护,试想如果存在多个状态字段(status、type等),则实体对象的状态是由多个状态字段组合而成的,每增加一个新的状态字段,都会导致状态的数量快速增加,这显然不是我们想看到的。

From:https://www.cnblogs.com/jilodream/p/18409656
本文地址: http://shuzixingkong.net/article/1895
0评论
提交 加载更多评论
其他文章 痞子衡嵌入式:在MDK开发环境下自定义安装与切换不同编译器版本的方法
大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是在MDK开发环境下自定义安装与切换不同编译器版本的方法。 Keil MDK 想必是嵌入式开发者最熟悉的工具之一了,自 2005 年 Arm 公司收购 Keil 公司之后,MDK 就走上了发展快车道,从 v2.50a 一路狂奔到现在最新的
痞子衡嵌入式:在MDK开发环境下自定义安装与切换不同编译器版本的方法 痞子衡嵌入式:在MDK开发环境下自定义安装与切换不同编译器版本的方法 痞子衡嵌入式:在MDK开发环境下自定义安装与切换不同编译器版本的方法
架构师备考的一些思考(二)
前言 以我的视野来看,部长或技术总监这种岗位还是比较难竞争的,换言之,程序员的上升空间比较窄,如果想要拿到高级岗位,最好的是工作三五年后就转项目经理,然后再往上爬。 架构师倒是也能晋升高级岗位,但就效率而言,是非常低的。就我的经验而言,架构师系的高级职位通常是技术管理一手抓,但这也代表着,责任更大,
架构师备考的一些思考(二)
在 Web 中判断页面是不是刷新
在 Web 开发中,我们经常需要区分用户是否通过刷新操作重新加载了页面。这一操作可能是由用户手动刷新(如按下 F5 键或点击浏览器刷新按钮)或通过浏览器自动重新加载。判断页面是否刷新有助于开发者优化用户体验,例如在使用 vue 的时候需要进行权限控制,就需要判断在刷新后根据登录者的权限去添加对应的路
在 Web 中判断页面是不是刷新 在 Web 中判断页面是不是刷新 在 Web 中判断页面是不是刷新
鸿蒙系统(HarmonyOS)全局弹窗实现
全局弹窗相对于自定义弹窗有以下优点: 封装更彻底,一行代码就能调用 跟组件耦合度低,只需要传入组件的UIContext对象,不需要跟自定义弹窗一样需要在组件内部实例化CustomDialogController对象 全局弹窗是鸿蒙在API 12增加的,PromptAction对象增加了openCus
鸿蒙系统(HarmonyOS)全局弹窗实现 鸿蒙系统(HarmonyOS)全局弹窗实现
Redis 入门 - C#|.NET Core客户端库六种选择
介绍了6款.NET系Redis客户端库:ServiceStack.Redis、StackExchange.Redis、CSRedisCore、FreeRedis、NewLife.Redis、BeetleX.Redis,各具特色,如商业支持、高性能、高并发、低延迟等,适合不同场景和需求。
Redis 入门 - C#|.NET Core客户端库六种选择 Redis 入门 - C#|.NET Core客户端库六种选择 Redis 入门 - C#|.NET Core客户端库六种选择
Redis、Nginx、SQLite、Elasticsearch等开源软件成功的原因及它们对IT技术人员的启示
引言 这些年在自研产品,对于如何做好产品进行了一些思考。随着开源软件的蓬勃发展,许多开源项目已经成为IT行业的核心组成部分。像Redis、Nginx、SQLite、Elasticsearch这些知名的开源软件,已经成为了开发者的首选工具。这些开源软件不仅在技术性能上取得了重大突破,还在社区建设、生态
论文阅读翻译之Deep reinforcement learning from human preferences
论文阅读翻译之Deep reinforcement learning from human preferences 关于 首次发表日期:2024-09-11 论文原文链接:https://arxiv.org/abs/1706.03741 论文arxiv首次提交日期:12 Jun 2017 使用KIM
论文阅读翻译之Deep reinforcement learning from human preferences
使用VSCode搭建UniApp + TS + Vue3 + Vite项目
`uniapp`是一个使用Vue.js开发所有前端应用的框架,开发者编写一套代码,可发布到iOS、Android、以及各种小程序。深受广大前端开发者的喜爱。`uniapp`官方也提供了自己的IDE工具`HBuilderX`,可以快速开发`uniapp`项目。但是很多前端的同学已经比较习惯使用`VSC
使用VSCode搭建UniApp + TS + Vue3 + Vite项目 使用VSCode搭建UniApp + TS + Vue3 + Vite项目 使用VSCode搭建UniApp + TS + Vue3 + Vite项目