状态模式

一、状态模式

状态模式(State Pattern)属于对象行为型模式,别名为状态对象(Objects for States)。
很多情况下,一个对象的行为取决于一个或多个动态变化的属性,这样的属性叫作状态,这样的对象叫作有状态的(Stateful)对象,对象状态是从事先定义好的一系列值中取出的。
定义对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。
使用频率:3星
模式结构
1、环境类(Context)角色:也称为上下文,它定义了客户端需要的接口,内部维护一个当前状态,并负责具体状态的切换。
2、抽象状态(State)角色:定义一个接口,用以封装环境对象中的特定状态所对应的行为,可以有一个或多个行为。
3、具体状态(Concrete State)角色:实现抽象状态所对应的行为,并且在需要的情况下进行状态切换。
状态模式结构图
在这里插入图片描述
优点
1、结构清晰,状态模式将与特定状态相关的行为局部化到一个状态中,并且将不同状态的行为分割开来,满足“单一职责原则”。
2、将状态转换显示化,减少对象间的相互依赖。将不同的状态引入独立的对象中会使得状态转换变得更加明确,且减少对象间的相互依赖。
3、状态类职责明确,有利于程序的扩展。通过定义新的子类很容易地增加新的状态和转换。
缺点
1、状态模式的使用必然会增加系统的类与对象的个数。
2、状态模式的结构与实现都较为复杂,如果使用不当会导致程序结构和代码的混乱。
3、状态模式对开闭原则的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源码,否则无法切换到新增状态,而且修改某个状态类的行为也需要修改对应类的源码。
应用场景
1、当一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为时,就可以考虑使用状态模式。
2、一个操作中含有庞大的分支结构,并且这些分支决定于对象的状态时。

二、状态模式实例之银行账户

1.实例说明

某银行系统中,我们定义账户的三种状态:
1、如果账户(Account)中余额(balance)大于等于0,此时账户的状态为绿色(GreenState),即正常状态,表示既可以向该账户存款(deposit)也可以从该账户取款(withdraw)
2、如果账户中余额小于0,并且大于等于-1000,则账户状态为黄色,即欠费状态,此时既可以向该账户存款也可以取款
3、如果账户余额小于-1000,那么账户状态为红色,即透支状态,此时只能存款不能取款
现使用状态模式实现状态转化问题,用户只需要执行简单存款取款操作,系统根据余额数量自动转换到相应的状态。

2.实例类图

在这里插入图片描述

3.实例代码

本例中,Account充当环境角色,AccountState充当抽象状态角色,YellowState、GreenState和RedState充当具体状态角色。

//银行账户:环境类
class Account{
    private AccountState state;
    private String owner;
    public Account(String owner,double init){
        this.owner=owner;
        this.state=new GreenState(init,this);
        System.out.println(this.owner+"开户,初始金额为:"+init);
        System.out.println("------------------------------------");
    }
    public void setState(AccountState state){
        this.state=state;
    }
    public void deposit(double amount){
        System.out.println(this.owner+"存款"+amount);
        state.deposit(amount);
        System.out.println("现在余额为:"+state.balance);
        System.out.println("现在账户状态为:"+state.getClass().getName());
        System.out.println("------------------------------------");
    }

    public void withdraw(double amount){
        System.out.println(this.owner+"取款"+amount);
        state.withdraw(amount);
        System.out.println("现在余额为:"+state.balance);
        System.out.println("现在账户状态为:"+state.getClass().getName());
        System.out.println("------------------------------------");
    }
}

//抽象状态类
abstract class AccountState{
    protected Account acc;
    protected double balance;
    public abstract void deposit(double amount);
    public abstract void withdraw(double amount);
    public abstract void stateCheck();
}

//绿色状态:具体状态类
class GreenState extends AccountState{
    public GreenState(AccountState state) {
        this.balance=state.balance;
        this.acc=state.acc;
    }
    public GreenState(double balance, Account acc) {
        this.balance=balance;
        this.acc=acc;
    }
    @Override
    public void deposit(double amount) {
        this.balance+=amount;
        stateCheck();
    }

    @Override
    public void withdraw(double amount) {
        this.balance-=amount;
        stateCheck();
    }

    @Override
    public void stateCheck() {
        if(balance>=-1000 && balance<0){
            acc.setState(new YellowState(this));
        }else if(balance<-1000){
            acc.setState(new RedState(this));
        }
    }
}

//黄色状态:具体状态类
class YellowState extends AccountState{
    public YellowState(AccountState state) {
        this.balance=state.balance;
        this.acc=state.acc;
    }
    @Override
    public void deposit(double amount) {
        this.balance+=amount;
        stateCheck();
    }

    @Override
    public void withdraw(double amount) {
        this.balance-=amount;
        stateCheck();
    }

    @Override
    public void stateCheck() {
        if(balance>=0){
            acc.setState(new GreenState(this));
        }else if(balance<-1000){
            acc.setState(new RedState(this));
        }
    }
}

//红色状态:具体状态类
class RedState extends AccountState{
    public RedState(AccountState state) {
        this.balance=state.balance;
        this.acc=state.acc;
    }
    @Override
    public void deposit(double amount) {
        this.balance+=amount;
        stateCheck();
    }

    @Override
    public void withdraw(double amount) {
        System.out.println("账户被冻结,取款失败!");
    }

    @Override
    public void stateCheck() {
        if(balance>=0){
            acc.setState(new GreenState(this));
        }else if(balance>=-1000){
            acc.setState(new YellowState(this));
        }
    }
}

客户端测试:

public class Client {
    public static void main(String[] args) {
        Account acc = new Account("Regan",1000.0);
        acc.deposit(100);
        acc.withdraw(2000);
        acc.deposit(100);
        acc.withdraw(500);
        acc.withdraw(100);
    }
}

运行结果:

Regan开户,初始金额为:1000.0
------------------------------------
Regan存款100.0
现在余额为:1100.0
现在账户状态为:GreenState
------------------------------------
Regan取款2000.0
现在余额为:-900.0
现在账户状态为:YellowState
------------------------------------
Regan存款100.0
现在余额为:-800.0
现在账户状态为:YellowState
------------------------------------
Regan取款500.0
现在余额为:-1300.0
现在账户状态为:RedState
------------------------------------
Regan取款100.0
账户被冻结,取款失败!
现在余额为:-1300.0
现在账户状态为:RedState
------------------------------------

参考文献

【1】状态模式(详解版)
【2】设计模式实训教程(第2版) 刘伟 编著 清华大学出版社

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值