状态模式-举例

在软件系统中,有些对象也像水一样具有多种状态,
这些状态在某些情况下能够相互转换,
而且对象在不同的状态下也将具有不同的行为。

参考日志来设置状态。
如何判断一个设计模式是行为模式还是什么其他模式?
什么叫行为模式?
行为模式关注对象之间的通讯、职责分配和算法的抽象。它主要解决
的是对象之间的协作问题,确保对象能够协同工作而不紧密耦合。

状态模式:允许一个对象在其内部状态改变时改变它的行为,对象
看起来似乎修改它的类。其别名为状态对象,状态模式是一种
状态行为模式。

某银行要开发一套信用卡业务系统,银行账户(Account)是该系统的核心类之一,通过分析,账户存在三种状态,且在不同状态下账户存在不同的行为,具体说明如下:(1) 如果账户中余额大于等于0,则账户的状态为正常状态(Normal State),此时用户既可以向该账户存款也可以从该账户取款;(2) 如果账户中余额小于0,并且大于-2000,则账户的状态为透支状态(Overdraft State),此时用户既可以向该账户存款也可以从该账户取款,但需要按天计算利息;(3) 如果账户中余额等于-2000,那么账户的状态为受限状态(Restricted State),此时用户只能向该账户存款,不能再从中取款,同时也将按天计算利息;(4) 根据余额的不同,以上三种状态可发生相互转换。

NormalState表示正常状态,OverdraftState表示透支状态,RestrictedState表示受限状态,在这三种状态下账户对象拥有不同的行为,方法deposit()用于存款,withdraw()用于取款,computeInterest()用于计算利息,stateCheck()用于在每一次执行存款和取款操作后根据余额来判断是否要进行状态转换并实现状态转换,相同的方法在不同的状态中可能会有不同的实现。

客户端代码

我们客户端直接操作一个账户对象,进行取款存款操作。但是随着操作的进行,账户内部一直在进行账户状态的维护。但是客户端没有任何感知,也不需要关心。

package behavioral.state;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();}
}

3)账户类代码

账户类组合了一个AccountState类,用于标识当前账户的状态,同时对账户发起操作请求时,根据不同的账户状态,相应的操作及权限限制也不同。这个根据不同状态做出不同操作的实现原理是多态。

package behavioral.state;//银行账户:环境类
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);state.deposit(amount); //调用状态对象的deposit()方法System.out.println("现在余额为"+ this.balance);System.out.println("现在帐户状态为"+ this.state.getClass().getSimpleName());System.out.println("---------------------------------------------");}public void withdraw(double amount) {System.out.println(this.owner + "取款" + amount);state.withdraw(amount); //调用状态对象的withdraw()方法System.out.println("现在余额为"+ this.balance);System.out.println("现在帐户状态为"+ this. state.getClass().getSimpleName());System.out.println("---------------------------------------------");}public void computeInterest(){state.computeInterest(); //调用状态对象的computeInterest()方法}
}

账户状态抽象类

 在状态模式中,我们将对象在不同状态下的行为封装到不同的状态类中,为了让系统具有更好的灵活性和可扩展性,同时对各状态下的共有行为进行封装,我们需要对状态进行抽象,引入了抽象状态类角色。 

package behavioral.state;
//抽象状态类
public 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();//检查和切换状态
}

正常状态类代码

如果账户中余额大于等于0,则账户的状态为正常状态(Normal State),此时用户既可以向该账户存款也可以从该账户取款

package behavioral.state;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("操作受限!");}}
}

透支状态代码

如果账户中余额小于0,并且大于-2000,则账户的状态为透支状态(Overdraft State),此时用户既可以向该账户存款也可以从该账户取款,但需要按天计算利息;

package behavioral.state;
//透支状态:具体状态类
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("操作受限!");}}
}

7)受限状态代码

如果账户中余额等于-2000,那么账户的状态为受限状态(Restricted State),此时用户只能向该账户存款,不能再从中取款,同时也将按天计算利息;

package behavioral.state;
//受限状态:具体状态类
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));}}
}

stateCheck()状态监测类用于监测当前账户金额情况,做出相应的状态切换操作。该方法也可以放在Accout类中。

https://github.com/phs999/DesignPatterns/tree/8ed9fd54d05d7da99833b6fa89e081c21938481b/design_pattern/src/behavioral/state

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

核心原理还是面向接口编程,多态。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

蓝桥圣诞树(C++)

问题描述 输入样例&#xff1a; 1 3 101 1 2 2 3 输出样例&#xff1a; YES 思路&#xff1a; 这道题还是比较好想的&#xff0c;因为它构造的二叉树是用边连接起来的&#xff0c;不是像之前一样从上到下从左到右按编号构造的&#xff0c;所以可以用邻接表来存每个点还有边&am…

[spark] 将dataframe中的数据插入到mysql

文章目录 分区写入 foreachPartition直接写入 write.jdbc()有没有插入成功在插入时记录行数 累加器 分区写入 foreachPartition 在Spark中&#xff0c;你可以使用foreachPartition或foreach来将DataFrame中的数据插入到MySQL数据库。以下是一个基本的Scala代码示例&#xff0c…

模板 BIEE (一):模板插入数据遇到的问题和解决方案

1 说明 1.1 环境 BIEE: Oracle Business Intelligence Enterprise Edition(Oracle商业智能企业版) 版本: OBIEE 12c Server 版本: 基于Oracle Analytics Server 6.4.0 版本 模板: 制造→生产成本→按前 10 个 GL 帐户列出的生产成本 1.2 问题 不熟悉Tools根据已插入的…

一个用于并发批量执行大量关键字的robot framework库。

这个库用于并发批量执行大量robot framework关键字。从而缩短案例执行时间。 使用concurrent.futures.ProcessPoolExecutor进程池并发执行同一个robot framework关键字很多次。 源代码如下&#xff1a; import concurrent.futuresfrom robot.libraries.BuiltIn import Built…

腾讯云价格计算器,一键计算精准报价,好用!

腾讯云价格计算器&#xff1a;可以计算腾讯云服务器不同CVM实例规格、CPU内存、公网带宽和系统盘费用明细表&#xff0c;可以一键计算出精准报价明细表&#xff0c;腾讯云服务器网txyfwq.com分享大家腾讯云服务器价格计算器入口链接、使用方法及限制说明&#xff1a; 腾讯云服…

网络攻击之-暴力破解/密码喷射流量告警运营分析篇

本文从暴力破解/密码喷射的定义,暴力破解/密码喷射的流量数据包示例,暴力破解/密码喷射的suricata规则,暴力破解/密码喷射的告警研判,暴力破解/密码喷射的处置建议等几个方面阐述如何通过IDS/NDR,态势感知等流量平台的暴力破解/密码喷射类型的告警的线索,开展日常安全运营…

【SD】语法格式 分析

正确语法&#xff1a; //人物 best quality,masterpiece,solo,1boy,male focus, //人物形容 blue long hair,katana,muscular,fingerlessgloves,samurai,japanese armor,chibi,full body,blood, //背景 模型 red background,<lora:CHIBI:0.35>, 错误语法&#…

D. Unnatural Language Processing

题目&#xff1a; D. Unnatural Language Processing 每次测试的时间限制1秒钟 每次测试的内存限制256兆字节 投入标准输入 输出标准输出 露拉觉得很无聊&#xff0c;决定用这五个字母创造一种简单的语言a, b, c, d, e。有两种类型的信件: 元音—信件a和e。他们由以下人员代表…

Python 操作 MySQL:使用 mysql-connector-python 操作 MySQL 数据库

大家好&#xff0c;我是水滴~~ 当涉及到使用 Python 操作 MySQL 数据库时&#xff0c;mysql-connector-python 库是一个强大而常用的选择。该库提供了与 MySQL 数据库的交互功能&#xff0c;使您能够执行各种数据库操作&#xff0c;如连接数据库、执行查询和插入数据等。在本文…

第十一章 Stream消息驱动

Stream消息驱动 gitee:springcloud_study: springcloud&#xff1a;服务集群、注册中心、配置中心&#xff08;热更新&#xff09;、服务网关&#xff08;校验、路由、负载均衡&#xff09;、分布式缓存、分布式搜索、消息队列&#xff08;异步通信&#xff09;、数据库集群、…

maven命令行安装依赖测试

mvn dependency:get -DgroupIdorg.springframework -DartifactIdspring-core -Dversion5.3.9作用&#xff1a;可用于测试配置环境变量后&#xff0c;能否下载依赖到本地仓库

前后端分离架构的特点以及优缺点

文章目录 一、前后端不分离架构(传统单体结构)1.1 什么是前后端不分离1.2 工作原理1.3 前后端不分离的优缺点1.4 应用场景 二、前后端分离架构2.1 为什么要前后端分离2.2 什么是前后端分离2.3 工作原理2.4 前后端分离的优缺点 参考资料 一、前后端不分离架构(传统单体结构) 首…

【linux】cut的基本使用

cut主要用于按列切分文本行&#xff0c;并输出指定的字段&#xff0c;这是类unix系统中常用的文本处理工具。 基本使用 首先随便去网上找个文本或者列表文件 如果使用cat看文本的话就是这样的 sh-3.2# cat data.csv Name,Age,City,Salary Alice,30,New York,70000 Bob,25,L…

C++ 侯捷 内存管理

C 的内存获取机制&#xff1a; void* p1 malloc(512); free(p1);complex<int>* p2 new complex<int>; delete p2;void* p3 ::operator new(512); ::operator delete(p3);//GNUC void* p4 alloc::allocate(512); alloc::deallocate(p4, 512);//GNUC4.9 void* p5…

Hbase详解

Hbase 概念 base 是分布式、面向列的开源数据库&#xff08;其实准确的说是面向列族&#xff09;。HDFS 为 Hbase 提供可靠的底层数据存储服务&#xff0c;MapReduce 为 Hbase 提供高性能的计算能力&#xff0c;Zookeeper 为 Hbase 提供稳定服务和 Failover 机制&#xff0c;…

OR-NeRF论文笔记

OR-NeRF论文笔记 文章目录 OR-NeRF论文笔记论文概述Abstract1 Introduction2 Related Work3 Background4 Method4.1 Multiview Segmentation4.2 Scene Object Removal 5 ExperimentsDatasetsMetricsMultiview SegmentationScene Object Removal 6 Conclusion 论文概述 目的&am…

Redis 笔记

文章目录 安装 & 启动杂乱String字符串 key-valueList 有序重复列表Set 无序不重复列表SortedSet 有序集合Hash 哈希Stream 消息队列订阅模式 学习地址&#xff1a;https://www.bilibili.com/video/BV1Jj411D7oG/ 安装 & 启动 安装包地址&#xff1a; https://github.…

【软件工程】漫谈增量过程模型:软件开发的逐步之道

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a; 软件工程 ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言&#xff1a; 正文 增量过程模型&#xff08;Incremental Process Model&#xff09; 主要特点和阶段&#xff1a; 优点&#xff1…

TCP 协议为什么要设计三次握手 TCP 协议,是一种可靠的,基于字节流的,面向连接的传输层协议。

文章目录 TCP 协议为什么要设计三次握手TCP 协议&#xff0c;是一种可靠的&#xff0c;基于字节流的&#xff0c;面向连接的传输层协议。TCP 通信双方的数据传输是通过字节流来实现传输的客户端向服务端发送连接请求并携带同步序列号 SYN。 今天我们来谈谈tcp的三次握手 TCP 协…

C++ dynamic_cast学习

dynamic_cast是将一个基类对象指针(或引用)转换到继承类指针; 可以在执行期决定真正的类型; 与static_cast一样,dynamic_cast的转换也需要目标类型和源对象有一定的关系:继承关系; 更准确的说,dynamic_cast是用来检查两者是否有继承关系; 用法 dynamic_cast <ty…