设计模式之状态模式(下)

3)共享状态
1.概述

在某些情况下,多个环境对象可能需要共享同一个状态,如果希望在系统中实现多个环境对象共享一个或多个状态对象,那么需要将这些状态对象定义为环境类的静态成员对象。

2.案例

背景:要求两个开关对象要么都处于开的状态,要么都处于关的状态,在使用时它们的状态必须保持一致,开关可以由开转换到关,也可以由关转换到开。

3.结构图

在这里插入图片描述

4.代码实现

开关类Switch

public class Switch {
  //定义三个静态的状态对象
	private static State state,onState,offState; 
	private String name;
	
	public Switch(String name) {
		this.name = name;
		onState = new OnState();
		offState = new OffState();
		this.state = onState;
	}
 
	public void setState(State state) {
		this.state = state;
	}
 
	public static State getState(String type) {
		if (type.equalsIgnoreCase("on")) {
			return onState;
		}else {
			return offState;
		}
	}
		
  //打开开关
	public void on() {
		System.out.print(name);
		state.on(this);
	}
	
  //关闭开关
	public void off() {
		System.out.print(name);
		state.off(this);
	}
}

抽象状态类

abstract class State {
	public abstract void on(Switch s);
	public abstract void off(Switch s);
}

具体状态类

//打开状态
public class OnState extends State {
	public void on(Switch s) {
		System.out.println("已经打开!");
	}
	
	public void off(Switch s) {
		System.out.println("关闭!");
		s.setState(Switch.getState("off"));
	}
}
 
//关闭状态
public class OffState extends State {
	public void on(Switch s) {
		System.out.println("打开!");
		s.setState(Switch.getState("on"));
	}
	
	public void off(Switch s) {
		System.out.println("已经关闭!");
	}
}

客户端类

public class Client {
	public static void main(String[] args) {
	  // 开关1 和 开关2 共享了开、关的状态
		Switch s1,s2;
		s1=new Switch("开关1");
		s2=new Switch("开关2");
		
		s1.on();
		s2.on();
		s1.off();
		s2.off();
		s2.on();
		s1.on();	
	}
}
4)使用环境类实现状态转换
1.概述

由环境类Context作为一个状态管理器实现状态之间的转换。

2.优点

对于客户端来说,无须关心状态类,可以为环境类设置默认的状态类,而将状态的转换工作交给具体状态类或环境类来完成,具体的转换细节对于客户端而言是透明的。

3.缺点

增加新的具体状态类可能需要修改其他具体状态类或者环境类的源代码,否则系统无法转换到新增状态。

4.结构图

在这里插入图片描述

5.代码实现
//屏幕类
public class Screen {
  //枚举所有的状态,currentState表示当前状态
	private State currentState, normalState, largerState, largestState;
 
	public Screen() {
    	this.normalState = new NormalState(); //创建正常状态对象
    	this.largerState = new LargerState(); //创建二倍放大状态对象
    	this.largestState = new LargestState(); //创建四倍放大状态对象
    	this.currentState = normalState; //设置初始状态
    	this.currentState.display();
	}
	
	public void setState(State state) {
		this.currentState = state;
	}
	
    //单击事件处理方法,封转了对状态类中业务方法的调用和状态的转换
	public void onClick() {
    	if (this.currentState == normalState) {
    		this.setState(largerState);
    		this.currentState.display();
    	}else if (this.currentState == largerState) {
    		this.setState(largestState);
    		this.currentState.display();
    	}
    	else if (this.currentState == largestState) {
    		this.setState(normalState);
    		this.currentState.display();
    	}
	}
}
 
//抽象状态类
abstract class State {
	public abstract void display();
}
 
//正常状态类
public class NormalState extends State{
	public void display() {
		System.out.println("正常大小!");
	}
}
 
//二倍状态类
public class LargerState extends State{
	public void display() {
		System.out.println("二倍大小!");
	}
}
 
//四倍状态类
public class LargestState extends State{
	public void display() {
		System.out.println("四倍大小!");
	}
}

客户端类

public class Client {
	public static void main(String[] args) {
		Screen screen = new Screen();
		screen.onClick();
		screen.onClick();
		screen.onClick();
	}
}

注意

所有的状态转换操作都由环境类Screen实现,此时,环境类充当了状态管理器角色。

如果需要增加新的状态,例如“八倍状态类”,需要修改环境类,这在一定程度上违背了“开闭原则”,但对其他状态类没有任何影响。

5)总结
1.优点
  • 封装了状态的转换规则,在状态模式中可以将状态的转换代码封装在环境类或者具体状态类中,可以对状态转换代码进行集中管理,而不是分散在一个个业务方法中。

  • 将所有与某个状态有关的行为放到一个类中,只需要注入一个不同的状态对象即可使环境对象拥有不同的行为。

  • 允许状态转换逻辑与状态对象合成一体,而不是提供一个巨大的条件语句块,状态模式可以避免使用庞大的条件语句来将业务方法和状态转换代码交织在一起。

  • 可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。

2.缺点
  • 状态模式的使用必然会增加系统中类和对象的个数,导致系统运行开销增大。

  • 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱,增加系统设计的难度。

  • 状态模式对“开闭原则”的支持并不好,增加新的状态类需要修改那些负责状态转换的源代码,否则无法转换到新增状态;而且修改某个状态类的行为也需修改对应类的源代码。

3.适用场景
  • 对象的行为依赖于它的状态(如某些属性值),状态的改变将导致行为的变化。

  • 在代码中包含大量与对象状态有关的条件语句,这些条件语句的出现,会导致代码的可维护性和灵活性变差,不能方便地增加和删除状态,并且导致客户类与类库之间的耦合增强。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

本地做好准备上传到Git分支,发现git上已经更新了,上传到dev分支

git add . git commit -m 备注 git pull --rebase origin dev 拉取dev上的代码合并到本地 git push -u origin dev推到远程dev上(注意着可能不是最后一步,先看完) 如果报错,意思是本地没有dev分支,没办法上传到git上…

获取钉钉群的 chatId

1、地址 获取地址 在代码发钉钉的地方找到 corpId。 填上后,会出现一个二维码,使用钉钉扫描二维码,就会出现你所在的群,点击,就能获取到 chatId

数据结构——单链表(C语言版)

文章目录 一、链表的概念及结构二、单链表的实现SList.h链表的打印申请新的结点链表的尾插链表的头插链表的尾删链表的头删链表的查找在指定位置之前插入数据在指定位置之后插入数据删除pos结点删除pos之后的结点销毁链表 三、完整源代码SList.hSList.ctest.c 一、链表的概念及…

自定义鼠标软件 SteerMouse最新完整激活版

SteerMouse是一款实用的Mac OS X系统辅助工具,可以帮助用户自定义鼠标和触控板的设置,提高使用效率。它提供了多种功能,如自定义按钮、滚轮和光标速度,以及调整灵敏度等,使用户能够根据自己的需求和习惯进行优化。 Ste…

振弦式裂缝计安装指南:使用灌浆锚头安装法

振弦式表面裂缝计作为一种精密的测量设备,在土木工程、建筑结构监测等领域发挥着重要的作用。为了确保裂缝计能够准确、稳定地工作,其安装过程尤为重要。本文将详细介绍振弦式表面裂缝计灌浆锚头的安装步骤,帮助大家更好地完成安装工作。 步骤…

启明智显技术分享|HMI工业级芯片Model3(简称M3芯片)PSRAM使用指南及PSRAM溢出如何进行问题定位

Model3芯片简介: 启明智显发布的HMI工业级芯片Model3(简称M3芯片)是一款高性能的显示交互和智能控制 MCU,采用国产自主高算力 RISC-V 内核,内置片上 1MB 大容量 SRAM 以及 64Mb PSRAM,并提供丰富的互联外设…

李彦宏官宣第二届“文心杯”创业大赛,最高投资奖励翻5倍达5000万

4月16日,百度创始人、董事长兼首席执行官李彦宏在Create 2024百度AI开发者大会上宣布,第二届“文心杯”创业大赛正式启动,参赛选手有机会获得最高5000万人民币投资。 李彦宏在Create 2024百度AI开发者大会的演讲主题是“人人都是开发者”&…

伦敦站:电子科技大学2024年全球人才推介会诚邀学者报名参会!

2024年4月24日,电子科技大学访英代表团一行将在伦敦举办人才推介交流会。届时,电子科技大学嘉宾将现场推介学校办学和人才队伍建设情况,宣讲学校人才引进政策,并与参会学者进行互动交流与洽谈。现热忱欢迎伦敦及周边地区学者报名参…

怎么申请OV证书

不同于DV SSL证书申请只需要验证域名所有权,申请OV SSL证书除了会验证域名之外,同时还会对申请企业的组织信息进行验证。本篇就给大家介绍一下如何申请OV SSL证书。 目前DV SSL证书和OV SSL证书的区别还是比较大的,DV和OV的区别:…

红帽认证考试流程指导

参加红帽认证考试涉及以下三个流程帐号和证件的准备 考试信息的填写 证书关联与下载 帐号和证件的准备RHN 帐号注册 在参加红帽官方培训和认证考试前需要您提前注册好红帽帐号(RHN) 访问 此页面 ,随后点击 Register for a Red Hat account 链接进行注册 注册时以下条…

BoostCompass( 查找功能实现 )

阅读导航 一、查找功能基本思路二、详细代码三、代码介绍四、运行结果 一、查找功能基本思路 通过实现一个基于倒排索引的搜索引擎,来提供高效、准确的搜索服务。其核心在于快速准确地从大量文档中检索出与用户查询关键词相关的文档,并按照相关性对结果…

【计算机考研】「软件工程」VS「电子信息」专硕有什么不同?

就今年的24国考来说,计算机技术(085404)能报的只是比计算机科学与技术少那么一点点(因为“计算机类”它都可以报,只有写计算机科学与技术的报不了)相对于其他天坑专业来说还是好很多的! 本人双…

制造企业研发设计资源用共享云桌面集中管控有哪些优势?

在制造企业上云的过程中,因为它们多用3D设计软件,所以选择一款高效、稳定、安全的云桌面产品显得尤为重要。云飞云共享云桌面作为一种新型的云桌面产品,正逐渐受到越来越多制造企业的青睐。那么,制造企业为什么要选云飞云共享云桌…

PaddleOCR训练自己模型(2)----参数配置及训练

一、介绍 paddleocr分为文字定位(Det)和文字识别(Rec)两个部分 二、定位模型训练 (1)Det预训练模型下载:https://paddleocr.bj.bcebos.com/PP-OCRv4/chinese/ch_PP-OCRv4_det_train.tar (2)下载完之后,…

(十一)C++自制植物大战僵尸游戏客户端更新实现

植物大战僵尸游戏开发教程专栏地址http://t.csdnimg.cn/cFP3z 更新检查 游戏启动后会下载服务器中的版本号然后与本地版本号进行对比,如果本地版本号小于服务器版本号就会弹出更新提示。让用户选择是否更新客户端。 在弹出的更新对话框中有显示最新版本更新的内容…

React-hooks:useRef

useRef文档 useRef 是一个ReactHook,它能帮助引用一个不需要渲染的值。 const ref useRef(initialValue)参数 initialValue:ref对象的 current 属性的初始值,可以是任意类型的值,这个参数在首次渲染后被忽略。 返回值 useRe…

Day99:云上攻防-云原生篇K8s安全实战场景攻击Pod污点Taint横向移动容器逃逸

目录 云原生-K8s安全-横向移动-污点Taint 云原生-K8s安全-Kubernetes实战场景 知识点: 1、云原生-K8s安全-横向移动-污点Taint 2、云原生-K8s安全-Kubernetes实战场景 云原生-K8s安全-横向移动-污点Taint 如何判断实战中能否利用污点Taint? 设置污点…

Java中的装箱和拆箱

本文先讲述装箱和拆箱最基本的东西,再来看一下面试笔试中经常遇到的与装箱、拆箱相关的问题。 目录: 装箱和拆箱概念 装箱和拆箱是如何实现的 面试中相关的问题 装箱和拆箱概念 Java为每种基本数据类型都提供了对应的包装器类型,至于为…

Xshell无法输入命令输入命令卡顿

Xshell是一款功能强大的终端模拟软件,可以让用户通过SSH、Telnet、Rlogin、SFTP等协议远程连接到Linux、Unix、Windows等服务器。然而,在使用Xshell的过程中,我们可能会遇到一些问题。比如输入不了命令,或者输入命令很卡。这些问题…

React-Redux(二)

​🌈个人主页:前端青山 🔥系列专栏:React篇 🔖人终将被年少不可得之物困其一生 依旧青山,本期给大家带来React篇专栏内容:React-Redux(二) 目录 react-redux 模块化 redux-thunk react-redu…