首页 > 编程语言 >设计模式-状态模式在Java中的使用示例-信用卡业务系统

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

时间:2024-04-24 17:24:46浏览次数:31  
标签:acc 状态 Java 示例 对象 void amount 设计模式 public

场景

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

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

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

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

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

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

状态模式(State Pattern):

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

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

 

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

● Context(环境类):

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

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

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

● State(抽象状态类):

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

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

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

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

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

注:

博客:
https://blog.csdn.net/badao_liumang_qizhi

实现

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

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

标签:acc,状态,Java,示例,对象,void,amount,设计模式,public
From: https://www.cnblogs.com/badaoliumangqizhi/p/18155901

相关文章

  • Windows中jps命令无法查看java进程问题
    参考 https://blog.csdn.net/qq_43413788/article/details/107772563原因:在Windows系统中,每个java进程启动之后都在%TMP%/hsperfdata_${user}(${user}为当前登录用户名)目录下建立一个以该java进程pid为文件名的文件,用以记录该java进程的一些信息。通常是因为没......
  • 最近5年133个Java面试问题列表
    来源:https://github.com/YHGui/easy-job/blob/master/面试题/133个Java常见面试题.mdJava面试随着时间的改变而改变。在过去的日子里,当你知道String和StringBuilder的区别(String类型和StringBuffer类型的主要性能区别其实在于String是不可变的对象。因此在每次对Stri......
  • Java引用拷贝、浅拷贝、深拷贝
    原链接在开发、刷题、面试中,我们可能会遇到将一个对象的属性赋值到另一个对象的情况,这种情况就叫做拷贝。拷贝与Java内存结构息息相关,搞懂Java深浅拷贝是很必要的!在拷贝中这里就分为引用拷贝、浅拷贝、深拷贝进行讲述。引用拷贝引用拷贝会生成一个新的对象引用地址,但是两个最......
  • Java 中什么是弱引用
    java弱引用对象被回收后,弱引用会变为null吗会。对象被回收后,空间会被回收,给空间地址分配的地址也会被回收,其引用都变成了null。什么是弱引用弱引用(WeakReference)是一种特殊的引用关系,在计算机程序设计中,与强引用相对。弱引用的主要特点是它不能确保其引用的对象不会被垃圾回收......
  • Java内部类和常用类
    Java内部类和常用类内部类概念:在一个类的内部在定义一个完整的类,与实例变量,实例方法同级别的类特点:编译后可生成独立的字节码文件内部类可以直接访问外部类的私有成员,而不破坏封装可为外部类提供必要功能组件内部类分类成员内部类静态内部类局部内部类匿名内部......
  • 解决 java 实体中用 LocalDateTime 在转换时候报错 Error attempting to get column
    java中的实体类用到了LocalDateTime类型。在转换时候报错Errorattemptingtogetcolumn‘XXX’fromresultset.Cause:java.sql.解决方法最为简单。是因为com.alibaba的版本问题。切换版本号到1.1.22即可消除问题<dependency><groupId>com.alibaba</gro......
  • java中的Context
    在java编程中,上下文(Context)是指程序运行时的环境和状态的集合。包括了类对象变量方法等运行时的相关数据在类中,我们可以通过this获取当前类的变量、方法的上下文,例如getset方法:this.val就是获取当前类的上下文。publicclassUser{privateStringname;publicStri......
  • 【Java注解】自定义注解的简单demo
    需求场景对于特定字段进行脱敏实现步骤首先创建注解@interface1importjava.lang.annotation.ElementType;2importjava.lang.annotation.Retention;3importjava.lang.annotation.RetentionPolicy;4importjava.lang.annotation.Target;56@Retention(Reten......
  • java操作ftp server
    参考:https://www.jianshu.com/p/2efc2669b736POM依赖<dependency><groupId>commons-net</groupId><artifactId>commons-net</artifactId><version>3.6</version></dep......
  • k8s Java 项目替换 jar 中的 class 文件
    背景紧急需求,客户需要立马上线docker包体积过大,远程不稳定,文件发不过去单点修改,风险低步骤1.获取pod所在宿主机podonhostkubectl-n$namespancegetpods-owide|grep$podname|grepRunning2.获取pod的容器cidkubectl-n$namespancedescribepo$podn......