设计模式-状态模式在Java中的使用示例-信用卡业务系统

news2024/11/17 0:01:52

场景

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

为了更好地对这些具有多种状态的对象进行设计,我们可以使用一种被称之为状态模式的设计模式。

状态模式用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题。当系统中某个对象存在多个状态,

这些状态之间可以进行转换,而且对象在不同状态下行为不相同时可以使用状态模式。

状态模式将一个对象的状态从该对象中分离出来,封装到专门的状态类中,使得对象状态可以灵活变化,

对于客户端而言,无须关心对象状态的转换以及对象所处的当前状态,无论对于何种状态的对象,客户端都可以一致处理。

状态模式(State Pattern):

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

状态模式是一种对象行为型模式。在状态模式中引入了抽象状态类和具体状态类,它们是状态模式的核心,其结构如图所示

在状态模式结构图中包含如下几个角色:

● Context(环境类):

环境类又称为上下文类,它是拥有多种状态的对象。由于环境类的状态存在多样性且在不同状态下对象的行为有所不同,

因此将状态独立出去形成单独的状态类。在环境类中维护一个抽象状态类State的实例,这个实例定义当前状态,

在具体实现时,它是一个State子类的对象。

● State(抽象状态类):

它用于定义一个接口以封装与环境类的一个特定状态相关的行为,在抽象状态类中声明了各种不同状态对应的方法,

而在其子类中实现类这些方法,由于不同状态下对象的行为可能不同,因此在不同子类中方法的实现可能存在不同,

相同的方法可以写在抽象状态类中。

● ConcreteState(具体状态类):它是抽象状态类的子类,每一个子类实现一个与环境类的一个

状态相关的行为,每一个具体状态类对应环境的一个具体状态,不同的具体状态类其行为有所不同。

注:

博客:
霸道流氓气质-CSDN博客

实现

1、示例场景

软件公司欲为某银行开发一套信用卡业务系统,银行账户(Account)是该系统的核心类之一,

通过分析,Sunny软件公司开发人员发现在该系统中,账户存在三种状态,且在不同状态下账户存在不同的行为,

具体说明如下:

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

(2) 如果账户中余额小于0,并且大于-2000,则账户的状态为透支状态(Overdraft State),此时用户既可以向该账户存款也可以从该账户取款,

但需要按天计算利息;

(3) 如果账户中余额等于-2000,那么账户的状态为受限状态(Restricted State),此时用户只能向该账户存款,不能再从中取款,

同时也将按天计算利息;

(4) 根据余额的不同,以上三种状态可发生相互转换。

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);
        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方法
    }
}

3、新建抽象状态类

/**
 * 抽象状态类
 */
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();
}

4、新建正常状态类:具体状态类

/**
 * 正常状态类:具体状态类
 */
public class NormalState extends AccountState{

    public NormalState(Account acc){
        this.acc = acc;
    }
    public NormalState(AccountState state){
        this.acc = state.acc;
    }
    @Override
    public void deposit(double amount) {
        acc.setBalance(acc.getBalance()+amount);
        stateCheck();
    }

    @Override
    public void withdraw(double amount) {
        acc.setBalance(acc.getBalance()-amount);
        stateCheck();
    }

    @Override
    public void computeInterest() {
        System.out.println("正常状态,无须支付利息!");
    }

    //状态转换
    @Override
    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("操作受限!");
        }
    }
}

5、新建透支状态类:具体状态类

//透支状态类:具体状态类
public class OverdraftState extends AccountState {

    public OverdraftState(AccountState state) {
        this.acc = state.acc;
    }

    @Override
    public void deposit(double amount) {
        acc.setBalance(acc.getBalance()+amount);
        stateCheck();
    }

    @Override
    public void withdraw(double amount) {
        acc.setBalance(acc.getBalance()-amount);
        stateCheck();
    }

    @Override
    public void computeInterest() {
        System.out.println("计算利息");
    }

    @Override
    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("操作受限!");
        }
    }
}

6、新建受限状态类:具体状态类

//受限状态:具体状态类
public class RestrictedState extends AccountState {

    public RestrictedState(AccountState state) {
        this.acc = state.acc;
    }

    @Override
    public void deposit(double amount) {
        acc.setBalance(acc.getBalance() + amount);
        stateCheck();
    }

    @Override
    public void withdraw(double amount) {
        System.out.println("账号受限,取款失败");
    }

    @Override
    public void computeInterest() {
        System.out.println("计算利息!");
    }

    @Override
    public void stateCheck() {
        if(acc.getBalance()>0){
            acc.setState(new NormalState(this));
        }else if(acc.getBalance()>-2000){
            acc.setState(new OverdraftState(this));
        }
    }
}

7、编写客户端测试

public class StatePatternClient {
    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();
    }
}

测试结果

张三开户,初始金额为0.0
------------------------------
张三存款1000.0
现在余额为1000.0
现在账户状态为NormalState
---------------------------------
张三取款2000.0
现在余额为-1000.0
现在账户状态为OverdraftState
---------------------------------
张三存款3000.0
现在余额为2000.0
现在账户状态为NormalState
---------------------------------
张三取款4000.0
现在余额为-2000.0
现在账户状态为RestrictedState
---------------------------------
张三取款1000.0
账号受限,取款失败
现在余额为-2000.0
现在账户状态为RestrictedState
---------------------------------
计算利息!

Process finished with exit code 0

8、总结

 状态模式将一个对象在不同状态下的不同行为封装在一个个状态类中,通过设置不同的状态对象可以让环境对象拥有不同的行为,

而状态转换的细节对于客户端而言是透明的,方便了客户端的使用。在实际开发中,状态模式具有较高的使用频率,

在工作流和游戏开发中状态模式都得到了广泛的应用,例如公文状态的转换、游戏中角色的升级等。

1. 主要优点

状态模式的主要优点如下:

(1) 封装了状态的转换规则,在状态模式中可以将状态的转换代码封装在环境类或者具体状态类中,可以对状态转换代码进行集中管理,

而不是分散在一个个业务方法中。

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

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

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

1. 主要缺点

状态模式的主要缺点如下:

(1) 状态模式的使用必然会增加系统中类和对象的个数,导致系统运行开销增大。

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

(3) 状态模式对“开闭原则”的支持并不太好,增加新的状态类需要修改那些负责状态转换的源代码,

否则无法转换到新增状态;而且修改某个状态类的行为也需修改对应类的源代码。

1. 适用场景

在以下情况下可以考虑使用状态模式

(1) 对象的行为依赖于它的状态(如某些属性值),状态的改变将导致行为的变化。

(2) 在代码中包含大量与对象状态有关的条件语句,这些条件语句的出现,会导致代码的可维护性和灵活性变差,不能方便地增加和删除状态,

并且导致客户类与类库之间的耦合增强。

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

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

相关文章

Adobe Illustrator 2024 v28.4.1 (macOS, Windows) - 矢量绘图

Adobe Illustrator 2024 v28.4.1 (macOS, Windows) - 矢量绘图 Acrobat、After Effects、Animate、Audition、Bridge、Character Animator、Dimension、Dreamweaver、Illustrator、InCopy、InDesign、Lightroom Classic、Media Encoder、Photoshop、Premiere Pro、Adobe XD 请…

【注解和反射】获取类运行时结构

继上一篇博客【注解和反射】类加载器-CSDN博客 目录 七、获取类运行时结构 测试 getFields()和getDeclaredFields() getMethods()和getDeclaredMethods() 七、获取类运行时结构 获取类运行时结构通常指的是在Java等面向对象编程语言中&#xff0c;使用反射&#xff08;Ref…

【git学习】Git 的基本操作

文章目录 &#x1f680;创建 Git 本地仓库&#x1f680;配置 Git&#x1f680;认识⼯作区、暂存区、版本库&#x1f680;添加⽂件操作 &#x1f680;创建 Git 本地仓库 仓库是进⾏版本控制的⼀个⽂件⽬录。我们要想对⽂件进⾏版本控制&#xff0c;就必须先创建⼀个仓库出来。 …

谷歌发布基于声学建模的无限虚拟房间增强现实鲁棒语音识别技术

声学室模拟允许在AR眼镜上以最少的真实数据进行训练&#xff0c;用于开发鲁棒的语音识别声音分离模型。 随着增强现实&#xff08;AR&#xff09;技术的强大和广泛应用&#xff0c;它能应用到各种日常情境中。我们对AR技术的潜能感到兴奋&#xff0c;并持续不断地开发和测试新…

web前端框架设计第六课-样式绑定

web前端框架设计第六课-样式绑定 一.预习笔记 1.class属性绑定 给P标签绑定一个类样式&#xff0c;类名为active。当active取值为true时&#xff0c;表示绑定样式成功&#xff0c;取值为false时&#xff0c;取消绑定 以对象形式给P标签绑定多个类样式 以数组形式给P标签绑定多…

网络安全新挑战:通用人工智能(AGI)等级保护指南

通用人工智能&#xff08;AGI&#xff09;的发展现状及趋势 随着2023年大语言模型应用的划时代突破&#xff0c;以ChatGPT为杰出代表的此类技术犹如一股洪流&#xff0c;彻底颠覆了人类与机器智能交互的疆界&#xff0c;引领通用人工智能&#xff08;AGI&#xff09;步入一个崭…

网络基础(day3)建议在电脑端注册登陆观看!!!

【 理论重点】 网络是什么&#xff1f; &#xff08;网络是载体&#xff0c;目的是传输互联网中的数据&#xff0c;数据是终端产生<手机、电脑、服务器等>。&#xff09; 如何组件网络&#xff08;良性网络架构&#xff09;&#xff1f;有网络架构思维&#xff0c;得按层…

宜搜科技死磕港交所上市:从搜索引擎到广告投放,业绩疲态凸显

近日&#xff0c;宜搜科技控股有限公司&#xff08;下称“宜搜科技”&#xff09;向港交所递交招股书&#xff0c;计划在香港主板上市&#xff0c;中银国际为其独家保荐人。 值得注意的是&#xff0c;宜搜科技已在资本市场辗转多年。该公司曾于2014年向纽交所递交上市申请&…

easyExcel快速入门

目录 &#x1f9c2;1.简单介绍 &#x1f32d;2.快速入门 &#x1f953;1.导入依赖 &#x1f37f;2.导出到excel &#x1f38f;3.读入数据 &#x1f389;4.下载 1.简单介绍 传统操作Excel大多都是利用Apach POl进行操作的,但是POI框架并不完善,使用过程非常繁琐且有较多…

Github进行fork后如何与原仓库同步

前言 fork了一个仓库以后怎么同步源仓库的代码&#xff1f; 步骤 1、执行命令 git remote -v 查看你的远程仓库的路径。 以一个实际例子说明&#xff0c; 来源仓库&#xff1a; TheFirstLineOfCode/basaltgit remote -v得到&#xff1a; origin https://github.com/ghmi…

Redis之路系列(5)功夫在诗外

5 拓展篇—功夫在诗外 6.0新特性 相对都比较鸡肋&#xff0c;谨慎在生产环境使用 ACL安全策略 Redis6版本推出了ACL(Access Control List)访问控制权限 的功能&#xff0c;基于此功能&#xff0c;可以设置多个用户&#xff0c;并且给每个用户单独设 置命令权限和数据权限。 …

机器学习/算法工程师面试题目与答案-深度学习部分1

机器学习/算法工程师面试题目与答案-深度学习部分 BatchNormalization的作用梯度消失循环神经网络&#xff0c;为什么好?什么是GroupConvolution什么是RNN神经网络中权重共享的是&#xff1f;神经网络激活函数&#xff1f;为什么在深度学习中常进行finetuning画GRU结构图什么是…

python+django校园社交高校交友网站2x7r5.

本课题使用Python语言进行开发。代码层面的操作主要在PyCharm中进行&#xff0c;将系统所使用到的表以及数据存储到MySQL数据库中&#xff0c;方便对数据进行操作本课题基于WEB的开发平台&#xff0c;设计的基本思路是&#xff1a; 前端&#xff1a;vue.jselementui 框架&#…

探索Web3:去中心化的互联网新时代

引言 在过去的几十年里&#xff0c;互联网已经改变了我们的生活方式、商业模式以及社交互动方式。然而&#xff0c;一个新的技术浪潮——Web3正在崭露头角&#xff0c;预示着一个去中心化的互联网新时代的来临。本文将深入探讨Web3技术的定义、特点以及其对未来互联网发展的影…

跨平台SIP 客户端-linphone下载、使用、开启视频H264

linphone 介绍 Linphone 是一种开源的语音和视频通信应用程序&#xff0c;它提供了基于互联网协议&#xff08;IP&#xff09;的实时通信功能。用于语音/视频通话、即时消息和电话会议的开源 SIP 电话。它适用于移动和桌面环境&#xff08;iOS、Android、GNU/Linux、macOS、Win…

【ensp】网关冗余vrrp实验

基础文字知识复习时&#xff0c;添加&#xff0c;下文仅拓扑以及核心配置以及结果分析 冗余路由器 核心代码&#xff1a; int g0/0/0 [R1-GigabitEthernet0/0/0]vrrp vrid 1 virtual-ip 192.168.10.1 ###设置虚拟ip [R1-GigabitEthernet0/0/0]vrrp vrid 1 priority 120 …

Flutter-自定义画板

效果 功能 支持绘制线、圆、矩形&#xff0c;支持拓展支持撤回上一步支持清空画板支持自定义画笔颜色&#xff0c;宽度 实现 定义绘制类型 /// 类型 enum ShapeType {//线line,//圆circle,//矩形rectangle,//拓展 }定义绘制抽象类 import dart:ui;/// 绘制抽象类 abstract…

云原生Service Mesh服务网格简单介绍

serviceMesh是什么 Service Mesh是一个用于处理服务间通信的基础设施层&#xff0c;旨在实现云原生应用复杂服务拓扑中的可靠请求传递。其基本构成是一组与应用一起部署的轻量级网络代理&#xff0c;这些代理对应用来说是透明的。Service Mesh通过统一的方式来控制和处理服务间…

数据结构-二叉树-链式

一、链式二叉树的结构 typedef int BTNodeDataType; typedef struct BTNode {BTNodeDataType data;struct BTNode* left;struct BTNode* right; }BTNode; 二叉树的前中后序遍历 前序&#xff1a;根左右 中序&#xff1a;左根右 后序&#xff1a;左右根 void PreOrder(BTNo…

大语言模型Ollama

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl Ollama简介 Ollama是一个开源的大语言模型平台&#xff0c;它允许用户在本地环境中运行、创建和共享大型语言模型。Ollama提供了丰富的功能和特性&#xff0c;使得用户可以…