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

状态模式
1)概述
1.定义

允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。

2.作用

状态模式用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题

3.方案

状态模式将一个对象的状态从该对象中分离出来,封装到专门的状态类中,使得对象状态可以灵活变化,对于客户端而言,无须关心对象状态的转换以及对象所处的当前状态,客户端都可以一致处理。

4.结构图

在这里插入图片描述

5.角色

Context(环境类):环境类又称为上下文类,它是拥有多种状态的对象,在环境类中维护一个抽象状态类State的实例,这个实例定义当前状态,在具体实现时,它是一个State子类的对象。

State(抽象状态类):定义一个接口以封装与环境类的一个特定状态相关的行为,在抽象状态类中声明了各种不同状态对应的方法,而在其子类中实现类这些方法,由于不同状态下对象的行为可能不同,因此在不同子类中方法的实现可能存在不同,相同的方法可以写在抽象状态类中

ConcreteState(具体状态类):它是抽象状态类的子类,每一个子类实现一个与环境类的一个状态相关的行为,每一个具体状态类对应环境的一个具体状态,不同的具体状态类其行为有所不同。

6.代码实现

抽象状态类

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

具体状态类

public class ConcreteState extends State {
	public void handle() {
		//方法具体实现代码
	}
}

环境类

public class Context {
  //维持一个对抽象状态对象的引用
	private State state; 
	//其他属性值,该属性值的变化可能会导致对象状态发生变化
	private int value; 
 
    //设置状态对象
	public void setState(State state) {
		this.state = state;
	}
 
	public void request() {
		//调用状态对象的业务方法
		state.handle(); 
	}
}

在状态模式的使用过程中,一个对象的状态之间还可以进行相互转换,通常有两种实现状态转换的方式。

统一由环境类来负责状态之间的转换:环境类充当了状态管理器(State Manager)角色,在环境类的业务方法中通过对某些属性值的判断实现状态转换,还可以提供一个专门的方法用于实现属性判断和状态转换。

	……
  public void changeState() {
		  //判断属性值,根据属性值进行状态转换
      if (value == 0){
			  this.setState(new ConcreteStateA());
		  }else if (value == 1){
			  this.setState(new ConcreteStateB());
		  }
	}
  ……

由具体状态类负责状态之间的转换:在具体状态类的业务方法中判断环境类的某些属性值再根据情况为环境类设置新的状态对象,实现状态转换,也可以提供一个专门的方法来负责属性值的判断和状态转换,此时,状态类与环境类之间存在依赖或关联关系,因为状态类需要访问环境类中的属性值。

	……
  public void changeState(Context ctx) {
		//根据环境对象中的属性值进行状态转换
    if (ctx.getValue() == 1){
			ctx.setState(new ConcreteStateB());
		}else if (ctx.getValue() == 2){
			ctx.setState(new ConcreteStateC());
		}
  }
  ……
2)完整解决方案
1.结构图

在这里插入图片描述

Account充当环境类角色,AccountState充当抽象状态角色,NormalState、OverdraftState和RestrictedState充当具体状态角色。

2.代码实现
//银行账户:环境类
public class Account {
  //维持一个对抽象状态对象的引用
	private AccountState state; 
	//开户名
	private String owner; 
	//账户余额
	private double balance = 0; 
	
	public Account(String owner,double init) {
		this.owner = owner;
		this.balance = balance;
		//设置初始状态
		this.state = new NormalState(this); 
		System.out.println(this.owner + "开户,初始金额为" + init);	
		System.out.println("---------------------------------------------");	
	}
	
	public double getBalance() {
		return this.balance;
	}
	
	public void setBalance(double balance) {
		this.balance = balance;
	}
	
	public void setState(AccountState state) {
		this.state = state;
	}
	
	public void deposit(double amount) {
		System.out.println(this.owner + "存款" + amount);
		//调用状态对象的deposit()方法
		state.deposit(amount); 
		System.out.println("现在余额为"+ this.balance);
		System.out.println("现在帐户状态为"+ this.state.getClass().getName());
		System.out.println("---------------------------------------------");			
	}
	
	public void withdraw(double amount) {
		System.out.println(this.owner + "取款" + amount);
		//调用状态对象的withdraw()方法
    state.withdraw(amount); 
		System.out.println("现在余额为"+ this.balance);
		System.out.println("现在帐户状态为"+ this. state.getClass().getName());		
		System.out.println("---------------------------------------------");
	}
	
	public void computeInterest()
	{ 
	  //调用状态对象的computeInterest()方法
		state.computeInterest(); 
	}
}
 
//抽象状态类
abstract class AccountState {
	protected Account acc;
	public abstract void deposit(double amount);
	public abstract void withdraw(double amount);
	public abstract void computeInterest();
	public abstract void stateCheck();
}
 
//正常状态:具体状态类
public class NormalState extends AccountState {
	public NormalState(Account acc) {
		this.acc = acc;
	}
 
  public NormalState(AccountState state) {
		this.acc = state.acc;
	}
		
	public void deposit(double amount) {
		acc.setBalance(acc.getBalance() + amount);
		stateCheck();
	}
	
	public void withdraw(double amount) {
		acc.setBalance(acc.getBalance() - amount);
		stateCheck();
	}
	
	public void computeInterest()
	{
		System.out.println("正常状态,无须支付利息!");
	}
	
    //状态转换
	public void stateCheck() {
		if (acc.getBalance() > -2000 && acc.getBalance() <= 0) {
			acc.setState(new OverdraftState(this));
		}
		else if (acc.getBalance() == -2000) {
			acc.setState(new RestrictedState(this));
		}
		else if (acc.getBalance() < -2000) {
			System.out.println("操作受限!");
		}	
	}   
}  
 
//透支状态:具体状态类
public class OverdraftState extends AccountState
{
	public OverdraftState(AccountState state) {
		this.acc = state.acc;
	}
	
	public void deposit(double amount) {
		acc.setBalance(acc.getBalance() + amount);
		stateCheck();
	}
	
	public void withdraw(double amount) {
		acc.setBalance(acc.getBalance() - amount);
		stateCheck();
	}
	
	public void computeInterest() {
		System.out.println("计算利息!");
	}
	
  //状态转换
	public void stateCheck() {
		if (acc.getBalance() > 0) {
			acc.setState(new NormalState(this));
		}
		else if (acc.getBalance() == -2000) {
			acc.setState(new RestrictedState(this));
		}
		else if (acc.getBalance() < -2000) {
			System.out.println("操作受限!");
		}
	}
}
 
//受限状态:具体状态类
public class RestrictedState extends AccountState {
	public RestrictedState(AccountState state) {
		this.acc = state.acc;
	}
	
	public void deposit(double amount) {
		acc.setBalance(acc.getBalance() + amount);
		stateCheck();
	}
	
	public void withdraw(double amount) {
		System.out.println("帐号受限,取款失败");
	}
	
	public void computeInterest() {
		System.out.println("计算利息!");
	}
	
    //状态转换
	public void stateCheck() {
		if(acc.getBalance() > 0) {
			acc.setState(new NormalState(this));
		}
		else if(acc.getBalance() > -2000) {
			acc.setState(new OverdraftState(this));
		}
	}
}

客户端测试类

public class Client {
	public static void main(String args[]) {
		Account acc = new Account("段誉",0.0);
		acc.deposit(1000);
		acc.withdraw(2000);
		acc.deposit(3000);
		acc.withdraw(4000);
		acc.withdraw(1000);
		acc.computeInterest();
	}
}

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

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

相关文章

VulNyx - Ready

目录 信息收集 arp nmap nikto Redis未授权访问漏洞 漏洞扫描 redis-cli 写入公钥 ssh连接 get root.txt 信息收集 arp ┌─[rootparrot]─[~/vulnyx] └──╼ #arp-scan -l Interface: enp0s3, type: EN10MB, MAC: 08:00:27:16:3d:f8, IPv4: 192.168.9.102 Starti…

网络协议安全:SSL/TLS协议详解,SSL协议执行原理、报文格式解析,Wireshark抓包分析SSL协议

「作者简介」&#xff1a;2022年北京冬奥会中国代表队&#xff0c;CSDN Top100&#xff0c;学习更多干货&#xff0c;请关注专栏《网络安全自学教程》 SSL协议 1、SSL协议发展史2、SSL协议执行过程3、SSL报文格式字段解析3.1、TLS报文头3.2、Handshake报文 4、Wireshark抓包分析…

基于STC12C5A60S2系列1T 8051单片机的带字库液晶显示器LCD12864数据传输并行模式显示16行点x16列点字模的功能

基于STC12C5A60S2系列1T 8051单片机的带字库液晶显示器LCD12864数据传输并行模式显示16行点x16列点字模的应用 STC12C5A60S2系列1T 8051单片机管脚图STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式及配置STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式介绍液晶显示…

javaweb在线拍卖系统

项目采用技术栈 htmlcssjs Vue2.js axios.js tomcat Servlet Mybatis Mysql 1.竞拍商品列表 实现多条件分页查询,头部根据是否登录作出不同的判断信息(登录或注销) 2.登录功能 3.竞拍页面 只有登录用户才能竞拍&#xff0c;出价记录需要实现关联用户查询 4.管理员登录增…

STM32芯片软复位导致SRAM2的值被擦除话题

1. 问题描述 客户在使用 STM32L433CCY6 开发过程中&#xff0c;出现软件复位后 SRAM2 里的值被擦除问题。 2. 问题确认 客户用同一版软件在两块板子上的表现还不一样&#xff0c;一块软件复位后 SRAM2 的值不会被擦除&#xff0c;另一块则会被擦除&#xff0c;并且确认被擦除…

光场相机建模与畸变校正改进方法

摘要&#xff1a;光场相机作为一种新型的成像系统&#xff0c;可以直接从一次曝光的图像中得到三维信息。为了能够更充分有效地利用光场数据包含的角度和位置信息&#xff0c;完成更加精准的场景深度计算&#xff0c;从而提升光场相机的三维重建的精度&#xff0c;需要实现精确…

Matlab方程组拟合【案例源码+视频教程】

专栏导读 作者简介&#xff1a;工学博士&#xff0c;高级工程师&#xff0c;专注于工业软件算法研究本文已收录于专栏&#xff1a;《复杂函数拟合案例分享》本专栏旨在提供 1.以案例的形式讲解各类复杂函数拟合的程序实现方法&#xff0c;并提供所有案例完整源码&#xff1b;2.…

llama_factory微调QWen1.5

GitHub - hiyouga/LLaMA-Factory: Unify Efficient Fine-Tuning of 100 LLMsUnify Efficient Fine-Tuning of 100 LLMs. Contribute to hiyouga/LLaMA-Factory development by creating an account on GitHub.https://github.com/hiyouga/LLaMA-FactoryQwen1.5 介绍 | QwenGITH…

Python(11):网络编程

文章目录 一、一些基本概念二、软件的开发架构&#xff08;c/s架构和b/s架构&#xff09;三、OSI模型四、socket套接字编程1.socket编程过程2.python中的socket编程 一、一些基本概念 来了解一些网络的基本概念 名词解释IP&#xff08;互联网协议地址&#xff09;IP用来标识网…

【Redis 神秘大陆】001 背景基础理论

一、背景&基础理论 1.1 什么是缓存 缓存&#xff1a;存储在计算机上的一个原始数据复制集&#xff0c;以便于访问——维基百科 1.2 为什么用缓存 提升用户体验&#xff1a; 【即效率、效益和基本主观满意度】CAST 使用者的状态、系统性能及环境&#xff0c;不同的人对于…

二维码生成器怎么做网址活码?链接制作二维码的方法

如何使用网址二维码生成器的功能来制作二维码呢&#xff1f;现在很多人会将网址生成二维码之后&#xff0c;分享给其他人通过手机扫码来打开网页获取内容&#xff0c;这种方式有利于网页的快速传播与分享&#xff0c;而且可以让更多的人同时访问对应的网页。那么网址转二维码的…

《二》Qt Creator工具介绍与使用

一、关于界面 点击文件--->新建文件或项目会出现如下图&#xff1a; 我们选择第一个 点击下一步下一步&#xff1a; 继续下一步直到结束&#xff1a; 二&#xff0c;具体文件介绍 我们点击pro查看以下 QT core gui第1行 表示使用qt的core和gui库&#xff0c;如果以后…

【C++程序员的自我修炼】日期类Date的实现

山河日月镌刻璀璨初心 八载春秋写就举世华章 目录 日期类Date的实现 构造函数 拷贝构造函数 获取月份天数的函数 日期类的检查 日期类的打印 运算符重载日期类的比较 运算符重载> 运算符重载 运算符的复用 日期加天数 日期减天数 ​编辑 运算符重载 运算符重载- 日期类的前…

11.盛最多水的容器(Java,双指针)

目录 题目描述&#xff1a;输入&#xff1a;输出&#xff1a;代码实现&#xff1a; 题目描述&#xff1a; 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同…

PHP01——php快速入门 之 在Mac上使用phpstudy快速搭建PHP环境

PHP01——php快速入门 之 在Mac上使用phpstudy快速搭建PHP环境 0. 前言1. 下载小皮面板1.1 下载phpstudy&#xff08;小皮面板&#xff09;1.2 启动、简单访问1.2.1 启动Apache1.2.2 访问1.2.3 访问自定义文件或页面 2. 创建网站2.1 创建网站2.2 可能遇到的问题2.2.1 hosts权限…

企业指标开发流程新主张

作为数据开发人员&#xff0c;你是否在指标开发过程中有过如下苦恼&#xff1a; Q1、 &#xff08;甲方&#xff09;业务人员&#xff1a;你这个指标计算逻辑不对&#xff0c;我们前期不是这么对的。 &#xff08;乙方&#xff09;卑微的你&#xff1a;Fu*k……我有录音。 …

创建和使用pipenv

创建pipenv 1.环境区别2.安装pipenv3.使用1.创建项目名称2.创建pipenv环境3.安装包1.安装包卡顿或卡住 4.查看包之间联系5.进入虚拟环境6.只安装dev环境的包7.常见的pipenv指令 1.环境区别 真实环境 真实环境可能被系统的其他软件依赖&#xff0c;下载包可能导致其他软件环境变…

Spark Standalone模式部署

准备至少2台虚拟机&#xff0c;装好linux系统&#xff0c;我装的是Ubuntu20.04。 1.修改主机名&#xff08;每台&#xff09; 1&#xff09;修改/etc/hostsname内容&#xff0c;主节点改为master&#xff0c;子节点改为slaver1 sudo vim /etc/hostname 2&#xff09;在/etc/…

【面试经典 150 | 数学】阶乘后的零

文章目录 写在前面Tag题目来源题目解读解题思路方法一&#xff1a;数学优化计算 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些对于本题涉及到的数据结…

防御性编程失败,我开始优化我写的多重 if-else 代码

最近防御性编程比较火&#xff0c;码农出身&#xff08;前后端内推&#xff09;的我不得试试 不出意外我被逮捕了&#xff0c;组内另外一位同事对我的代码进行了 CodeReview&#xff0c;我的防御性编程编程没有幸运逃脱&#xff0c;被标记上了“多重 if-else ”需要进行优化。 …