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

news/2024/9/23 5:19:17/
状态模式
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();}
}

http://www.ppmy.cn/news/1426979.html

相关文章

leetcode不同路径

. - 力扣&#xff08;LeetCode&#xff09; 62. 不同路径 中等 相关标签 相关企业 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下…

element-ui合计逻辑踩坑

element-ui合计逻辑踩坑 1.快速实现一个合计 ​ Element UI所提供的el-table中提供了方便快捷的合计逻辑实现&#xff1a; ​ https://element.eleme.cn/#/zh-CN/component/table ​ 此实现方法在官方文档中介绍详细&#xff0c;此处不多赘述。 ​ 这里需要注意&#xff0c…

K8S 亲和性与反亲和性

介绍 在 Kubernetes 中&#xff0c;亲和性&#xff08;Affinity&#xff09;是一种用于控制 Pod 调度的机制&#xff0c;它允许你指定 Pod 如何与节点进行互动&#xff0c;以便将 Pod 调度到合适的节点上。亲和性可以分为两种类型&#xff1a;节点亲和性&#xff08;Node Affi…

0-1 数据大屏——这样设计高质量可视化大屏

5 大指南塑造高阶可视化 可视化是个友好的媒介 理解数据是成为优秀媒介的关键 业务驱动下的设计策略 图扑设计的无限可能 创新思维让可视化更具价值 可视化是个友好的媒介 我们正处于一个数据泛滥的时代&#xff0c;随处可见数据的身影&#xff0c;更知其不可忽视的重要…

使用 Lua 协程处理异步回调函数

异步回调 项目使用 C Lua 方式&#xff0c;C 主要编写一些底层模块&#xff0c;通常提供异步的方式 Lua 脚本中&#xff0c;使用这些 C 导入的模块&#xff0c;和异步方式编写代码 一般的一次异步调用&#xff0c;通常还可以编写逻辑清晰的代码 但是会有些功能会比较复杂的…

Vue.js------Vue组件基础

能够理解Vue组件概念和作用能够掌握封装创建组件能力能够使用组件之间通信能够完成todo案例 一.Vue组件创建和使用 1.折叠面板-实现多个 创建一个文件夹demo 具体步骤请参考vue.js---vue基础 ⚫ 解决方案: 采用vue提供的单.vue文件-组件方式来封装一套然后复用 在component…

[蓝桥杯] 纸张尺寸(C语言)

题目链接 蓝桥杯2022年第十三届省赛真题-纸张尺寸 - C语言网 题目理解 输入一行包含一个字符串表示纸张的名称&#xff0c;该名称一定是 A0、A1、A2、A3、A4、A5、A6、A7、A8、A9 之一&#xff0c;输出两行&#xff0c;每行包含一个整数&#xff0c;依次表示长边和短边的长度…

重温《Effective Java》

如果忘掉其他的数据结构&#xff0c; 只留下一种&#xff0c;或许会是哈希表&#xff1b; 如果忘掉其他的安全技术&#xff0c;只留下一种&#xff0c;或许会是访问控制&#xff1b; 如果扔掉手中其他的Java 手册&#xff0c;只留下一本&#xff0c;对于期望写出高效而优雅代码…