2025/10/20日 每日总结 设计模式实践:状态模式玩转银行账户状态管理

设计模式实践:状态模式玩转银行账户状态管理

在软件开发中,当对象的行为依赖于其状态(如账户的正常/欠费/透支状态),且状态会随行为动态变化时,大量的if-else判断会让代码臃肿难维护。状态模式通过将“状态”封装为独立类,让对象在不同状态下的行为由对应状态类实现,实现状态与行为的解耦。本文以银行账户为例,用状态模式实现账户在不同余额状态下的存款、取款逻辑,带你直观感受状态模式的优雅。

一、状态模式核心思想

状态模式是一种行为型设计模式,核心目标是将对象的状态与行为分离,让状态决定行为,其关键结构包括:

  1. 环境类(Context):即状态的拥有者(如银行账户),持有当前状态对象,提供对外操作接口(存款、取款);

  2. 抽象状态(State):定义所有状态必须实现的行为接口(如存款、取款、状态检查);

  3. 具体状态(Concrete State):实现抽象状态接口,封装对应状态下的具体行为,负责状态转换判断。
    本次实践中,银行账户有三种状态,不同状态下操作权限不同:

  • 绿色状态(余额≥0):正常状态,支持存款、取款;

  • 蓝色状态(-1000≤余额<0):欠费状态,支持存款、取款(取款后余额不低于-1000);

  • 红色状态(余额<-1000):透支状态,仅支持存款,禁止取款。

    二、类图设计

    | AccountState | // 抽象状态接口
    +-------------------+
    
    
    
  • deposit(amount: double): void // 存款

  • withdraw(amount: double): void // 取款

  • checkState(): void // 检查状态转换

  • getStateName(): String // 获取状态名称
    +-------------------+
    ^
    |
    +-------+-------+ +-------+-------+ +-------+-------+
    | | | | | |
    | GreenState | | BlueState | | RedState | // 具体状态类
    +---------------+ +---------------+ +---------------+

  • account: Account - account: Account - account: Account

  • GreenState(account: Account) + BlueState(account: Account) + RedState(account: Account)

  • deposit(amount: double): void + deposit(amount: double): void + deposit(amount: double): void

  • withdraw(amount: double): void + withdraw(amount: double): void + withdraw(amount: double): void

  • checkState(): void + checkState(): void + checkState(): void

  • getStateName(): String + getStateName(): String + getStateName(): String
    +---------------+ +---------------+ +---------------+
    +-------------------+
    | Account | // 环境类:银行账户
    +-------------------+

  • accountNumber: String // 账号

  • owner: String // 户主

  • balance: double // 余额

  • state: AccountState // 当前状态
    +-------------------+

  • Account(accountNumber: String, owner: String, initialBalance: double) // 构造方法

  • deposit(amount: double): void // 存款接口

  • withdraw(amount: double): void // 取款接口

  • checkBalance(): void // 查询余额与状态

  • setState(state: AccountState): void // 设置当前状态

  • getBalance(): double // 获取余额(供状态类访问)

  • setBalance(balance: double): void // 设置余额(供状态类修改)
    +-------------------+

    ## 三、完整代码实现
    ### 1. 抽象状态接口(AccountState)
    定义所有状态必须实现的核心行为,统一状态类的接口规范。
    ```java
    /**
    * 抽象状态接口:定义账户状态的核心行为
    */
    public interface AccountState {
    // 存款操作
    void deposit(double amount);
    // 取款操作
    void withdraw(double amount);
    // 检查状态转换(余额变化后判断是否需要切换状态)
    void checkState();
    // 获取状态名称(用于显示)
    String getStateName();
    }
    

    2. 具体状态类(三种账户状态)

    分别实现抽象接口,封装对应状态下的存款、取款逻辑,以及状态转换判断。

    绿色状态(GreenState):正常状态(余额≥0)

    /**
    * 绿色状态:余额≥0,支持存款、取款(取款金额≤余额)
    */
    public class GreenState implements AccountState {
    private Account account; // 持有环境类引用,用于修改余额和状态
    public GreenState(Account account) {
    this.account = account;
    }
    @Override
    public void deposit(double amount) {
    // 存款:余额增加,后检查状态
    account.setBalance(account.getBalance() + amount);
    checkState();
    System.out.printf("存款成功,当前余额: %.2f%n", account.getBalance());
    }
    @Override
    public void withdraw(double amount) {
    if (amount <= account.getBalance()) {
    // 取款:余额减少,后检查状态
    account.setBalance(account.getBalance() - amount);
    checkState();
    System.out.printf("取款成功,当前余额: %.2f%n", account.getBalance());
    } else {
    System.out.println("取款失败:余额不足");
    }
    }
    @Override
    public void checkState() {
    // 状态转换判断:余额<0且≥-1000→蓝色状态;余额<-1000→红色状态
    if (account.getBalance() < 0 && account.getBalance() >= -1000) {
    account.setState(new BlueState(account));
    } else if (account.getBalance() < -1000) {
    account.setState(new RedState(account));
    }
    }
    @Override
    public String getStateName() {
    return "绿色状态(正常)";
    }
    }
    

    蓝色状态(BlueState):欠费状态(-1000≤余额<0)

    /**
    * 蓝色状态:-1000≤余额<0,支持存款、取款(取款后余额≥-1000)
    */
    public class BlueState implements AccountState {
    private Account account;
    public BlueState(Account account) {
    this.account = account;
    }
    @Override
    public void deposit(double amount) {
    account.setBalance(account.getBalance() + amount);
    checkState();
    System.out.printf("存款成功,当前余额: %.2f%n", account.getBalance());
    }
    @Override
    public void withdraw(double amount) {
    // 取款限制:余额-取款金额≥-1000
    if (account.getBalance() - amount >= -1000) {
    account.setBalance(account.getBalance() - amount);
    checkState();
    System.out.printf("取款成功,当前余额: %.2f%n", account.getBalance());
    } else {
    System.out.println("取款失败:超过透支限额");
    }
    }
    @Override
    public void checkState() {
    // 状态转换判断:余额≥0→绿色状态;余额<-1000→红色状态
    if (account.getBalance() >= 0) {
    account.setState(new GreenState(account));
    } else if (account.getBalance() < -1000) {
    account.setState(new RedState(account));
    }
    }
    @Override
    public String getStateName() {
    return "蓝色状态(欠费)";
    }
    }
    

    红色状态(RedState):透支状态(余额<-1000)

    /**
    * 红色状态:余额<-1000,仅支持存款,禁止取款
    */
    public class RedState implements AccountState {
    private Account account;
    public RedState(Account account) {
    this.account = account;
    }
    @Override
    public void deposit(double amount) {
    account.setBalance(account.getBalance() + amount);
    checkState();
    System.out.printf("存款成功,当前余额: %.2f%n", account.getBalance());
    }
    @Override
    public void withdraw(double amount) {
    System.out.println("取款失败:账户处于透支状态,只能存款");
    }
    @Override
    public void checkState() {
    // 状态转换判断:余额≥0→绿色状态;-1000≤余额<0→蓝色状态
    if (account.getBalance() >= 0) {
    account.setState(new GreenState(account));
    } else if (account.getBalance() >= -1000) {
    account.setState(new BlueState(account));
    }
    }
    @Override
    public String getStateName() {
    return "红色状态(透支)";
    }
    }
    

    3. 环境类(Account):银行账户

    持有当前状态对象,提供对外操作接口(存款、取款、查询),不关心具体状态逻辑,将行为委托给当前状态类。

    /**
    * 环境类:银行账户,状态的拥有者
    */
    public class Account {
    private String accountNumber; // 账号
    private String owner; // 户主
    private double balance; // 余额
    private AccountState state; // 当前状态
    // 构造方法:初始化账户信息,根据初始余额设置初始状态
    public Account(String accountNumber, String owner, double initialBalance) {
    this.accountNumber = accountNumber;
    this.owner = owner;
    this.balance = initialBalance;
    // 初始状态判断
    if (balance >= 0) {
    this.state = new GreenState(this);
    } else if (balance >= -1000) {
    this.state = new BlueState(this);
    } else {
    this.state = new RedState(this);
    }
    System.out.printf("%s 开户成功,初始余额: %.2f%n", owner, initialBalance);
    System.out.println("账户状态: " + state.getStateName());
    }
    // 存款:委托给当前状态类实现
    public void deposit(double amount) {
    if (amount <= 0) {
    System.out.println("存款金额必须大于0");
    return;
    }
    state.deposit(amount);
    }
    // 取款:委托给当前状态类实现
    public void withdraw(double amount) {
    if (amount <= 0) {
    System.out.println("取款金额必须大于0");
    return;
    }
    state.withdraw(amount);
    }
    // 查询余额与当前状态
    public void checkBalance() {
    System.out.printf("账户余额: %.2f%n", balance);
    System.out.println("当前状态: " + state.getStateName());
    }
    // Getter和Setter(供状态类访问和修改)
    public double getBalance() {
    return balance;
    }
    public void setBalance(double balance) {
    this.balance = balance;
    }
    public void setState(AccountState state) {
    this.state = state;
    System.out.println("账户状态已转换为: " + state.getStateName());
    }
    public String getAccountNumber() {
    return accountNumber;
    }
    public String getOwner() {
    return owner;
    }
    }
    

    4. 测试类(BankAccountTest)

    模拟不同场景下的账户操作,验证状态模式的状态转换和行为逻辑。

    /**
    * 测试类:验证银行账户状态模式的功能
    */
    public class BankAccountTest {
    public static void main(String[] args) {
    System.out.println("=== 银行账户状态模式测试 ===\n");
    // 测试用例1:正常账户操作(绿色状态→蓝色状态→绿色状态)
    System.out.println("测试用例1:正常账户操作");
    Account account1 = new Account("001", "张三", 1000);
    account1.deposit(500); // 余额1500(绿色)
    account1.withdraw(200); // 余额1300(绿色)
    account1.withdraw(2000); // 余额-700(转换为蓝色)
    account1.checkBalance();
    System.out.println();
    // 测试用例2:账户进入欠费状态(绿色→蓝色)
    System.out.println("测试用例2:账户进入欠费状态");
    Account account2 = new Account("002", "李四", 500);
    account2.withdraw(800); // 余额-300(蓝色)
    account2.withdraw(500); // 余额-800(仍为蓝色)
    account2.checkBalance();
    System.out.println();
    // 测试用例3:账户进入透支状态(绿色→红色→蓝色)
    System.out.println("测试用例3:账户进入透支状态");
    Account account3 = new Account("003", "王五", 200);
    account3.withdraw(1500); // 余额-1300(红色)
    account3.withdraw(100); // 红色状态禁止取款
    account3.deposit(800); // 余额-500(转换为蓝色)
    account3.checkBalance();
    System.out.println();
    // 测试用例4:从透支状态恢复(蓝色→绿色)
    System.out.println("测试用例4:从透支状态恢复");
    Account account4 = new Account("004", "赵六", -800); // 初始蓝色
    account4.checkBalance();
    account4.deposit(500); // 余额-300(仍为蓝色)
    account4.deposit(400); // 余额100(转换为绿色)
    account4.checkBalance();
    }
    }
    

    四、运行结果与验证

    === 银行账户状态模式测试 ===
    测试用例1:正常账户操作
    张三 开户成功,初始余额: 1000.00
    账户状态: 绿色状态(正常)
    存款成功,当前余额: 1500.00
    取款成功,当前余额: 1300.00
    取款成功,当前余额: -700.00
    账户状态已转换为: 蓝色状态(欠费)
    账户余额: -700.00
    当前状态: 蓝色状态(欠费)
    测试用例2:账户进入欠费状态
    李四 开户成功,初始余额: 500.00
    账户状态: 绿色状态(正常)
    取款成功,当前余额: -300.00
    账户状态已转换为: 蓝色状态(欠费)
    取款成功,当前余额: -800.00
    账户余额: -800.00
    当前状态: 蓝色状态(欠费)
    测试用例3:账户进入透支状态
    王五 开户成功,初始余额: 200.00
    账户状态: 绿色状态(正常)
    取款成功,当前余额: -1300.00
    账户状态已转换为: 红色状态(透支)
    取款失败:账户处于透支状态,只能存款
    存款成功,当前余额: -500.00
    账户状态已转换为: 蓝色状态(欠费)
    账户余额: -500.00
    当前状态: 蓝色状态(欠费)
    测试用例4:从透支状态恢复
    赵六 开户成功,初始余额: -800.00
    账户状态: 蓝色状态(欠费)
    账户余额: -800.00
    当前状态: 蓝色状态(欠费)
    存款成功,当前余额: -300.00
    存款成功,当前余额: 100.00
    账户状态已转换为: 绿色状态(正常)
    账户余额: 100.00
    当前状态: 绿色状态(正常)
    

    结果分析:

  1. 状态转换自动触发:存款/取款后,checkState()会自动判断余额,切换到对应状态;

  2. 行为与状态绑定:不同状态下的取款权限不同(红色禁止、蓝色限额、绿色无限制),逻辑封装在各自状态类中;

  3. 环境类无状态判断:Account类无需用if-else判断状态,所有行为委托给当前状态类,代码简洁。

五、状态模式的核心优势与适用场景

核心优势

  1. 消除大量条件判断:用状态类替代if-else,避免代码臃肿,提高可读性和维护性;

  2. 状态逻辑封装独立:每个状态的行为和转换规则封装在对应类中,符合“单一职责原则”;

  3. 扩展性强:新增状态(如“冻结状态”)只需新增具体状态类,无需修改环境类和其他状态类,符合“开闭原则”;

  4. 状态转换清晰:状态转换规则集中在checkState()方法,便于跟踪和修改。

适用场景

  1. 对象状态多且状态转换复杂:如订单状态(待支付→已支付→发货中→已完成)、设备状态(待机→运行→故障);

  2. 对象行为依赖于状态:不同状态下行为差异大,如账户、会员等级(普通→VIP→超级VIP);

  3. 避免条件判断膨胀:当if-elseswitch判断超过3个时,优先考虑状态模式。

六、实践总结

  1. 状态模式的核心是“状态决定行为,行为触发状态转换”,通过分离状态与环境类,让代码更优雅、易维护;

  2. 环境类持有当前状态对象,提供对外接口;具体状态类实现行为逻辑和状态转换,是模式的核心;

  3. 状态转换的触发时机:通常在行为执行后(如存款/取款后)调用checkState(),确保状态及时更新;

  4. 实际开发中,状态模式常与单例模式结合(同一状态全局复用一个实例),减少对象创建开销。
    通过本次银行账户的实践,我深刻体会到状态模式在复杂状态管理中的价值。它不仅解决了条件判断臃肿的问题,还让状态逻辑的扩展变得简单,尤其适合状态多变的业务场景。

posted @ 2025-12-29 14:41  Moonbeamsc  阅读(1)  评论(0)    收藏  举报
返回顶端