状态模式-对象状态及其转换

这篇具有很好参考价值的文章主要介绍了状态模式-对象状态及其转换。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

 某信用卡业务系统,银行账户存在3种状态,且在不同状态下存在不同的行为:

1)正常状态(余额大等于0),用户可以存款也可以取款;

2)透支状态(余额小于0且大于-2000),用户可以存款也可以取款,但需要对欠款支付利息。

3)受限状态(余额小等于-2000),用户只能存款,还需要对欠款支付利息。

状态模式-对象状态及其转换,# 设计模式的艺术,状态模式,设计模式

图 伪代码实现上述需求

上面代码存在以下问题:

1)获取状态时,有好多个if分支,如果再增加几个状态,则需要增加判断条件,同时也不符合开闭原则。

2)在进行存取款操作时,有对状态进行判断的条件,行为受到状态的限制。

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

1 状态模式

状态模式(State Pattern)允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的状态类。是一种对象行为型模式。

状态模式-对象状态及其转换,# 设计模式的艺术,状态模式,设计模式

图 状态模式UML

Context:环境类,是拥有多种状态的对象。由于环境类的状态存在多样性且在不同状态下对象的行为有所不同,因此将状态独立出去形成单独的状态类。

State:抽象状态类,用于定义一个接口以封装与环境类的一个特定状态相关的行为。在抽象状态类中声明各种不同状态对应的方法,而在其子类中实现这些方法。

ConcreteState:具体状态类,是抽象状态类的子类,每个子类实现与环境类的一个状态相关的行为。

public class UserAccount {

    private double balance;

    private CardState cardState;

    public UserAccount(double balance) {
        this.balance = balance;
        cardState = new NormalCardState(this);
    }

    public double getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        this.balance = balance;
    }

    public void deposit(double money) {
        System.out.println("存钱 " + money);
        cardState.deposit(money);
        changeState();
        System.out.println("信用卡余额:"+ balance + ",状态是:" + cardState.getState());
        System.out.println("------------------------------");
    }

    public void withdraw(double money) {
        if (balance - money < 0) {
            System.out.println("借钱 " + money + ",利息利率是0.01");
        } else {
            System.out.println("取款 " + money);
        }
        cardState.withdraw(money);
        changeState();
        System.out.println("信用卡余额:"+ balance + ",状态是:" + cardState.getState());
        System.out.println("------------------------------");
    }

    public void changeState() {
        if (balance > 0) {
            if (!"正常".equals(cardState.getState())) cardState = new NormalCardState(this);
        } else if (balance > -2000) {
            if (!"透支".equals(cardState.getState())) cardState = new OverdraftCardState(this);
        } else {
            if (!"受限".equals(cardState.getState())) cardState = new LimitationCardState(this);
        }
    }

    public void setCardState(CardState cardState) {
        this.cardState = cardState;
    }
}

public abstract class CardState {

    protected final UserAccount userAccount;

    public CardState(UserAccount userAccount) {
        this.userAccount = userAccount;
    }

    public abstract void deposit(double money); // 存款

    public abstract void withdraw(double money); // 取款

    public abstract void payInterest(); // 支付利息

    public abstract String getState(); // 获取状态

}

public class BankService {

    public static void main(String[] args) {
        // 开户
        UserAccount userAccount = new UserAccount(1000);
        userAccount.withdraw(500);
        userAccount.deposit(200);
        userAccount.withdraw(1000);
        userAccount.deposit(100);
        userAccount.withdraw(2000);
        userAccount.withdraw(500);
    }

}

//取款 500.0
//信用卡余额:500.0,状态是:正常
//------------------------------
//存钱 200.0
//信用卡余额:700.0,状态是:正常
//------------------------------
//借钱 1000.0,利息利率是0.01
//信用卡余额:-300.0,状态是:透支
//------------------------------
//存钱 100.0
//支付利息:-3.0
//信用卡余额:-203.0,状态是:透支
//------------------------------
//借钱 2000.0,利息利率是0.01
//支付利息:-2.0300000000000002
//信用卡余额:-2205.03,状态是:受限
//------------------------------
//借钱 500.0,利息利率是0.01
//该账户已受限,不能取款
//信用卡余额:-2205.03,状态是:受限
//------------------------------


public class NormalCardState extends CardState{

    public NormalCardState(UserAccount userAccount) {
        super(userAccount);
    }

    @Override
    public void deposit(double money) {
        userAccount.setBalance(userAccount.getBalance() + money);
    }

    @Override
    public void withdraw(double money) {
        userAccount.setBalance(userAccount.getBalance() - money);
    }

    @Override
    public void payInterest() {

    }

    @Override
    public String getState() {
        return "正常";
    }

}

public class OverdraftCardState extends CardState{

    public OverdraftCardState(UserAccount userAccount) {
        super(userAccount);
    }

    @Override
    public void deposit(double money) {
        payInterest();
        userAccount.setBalance(userAccount.getBalance() + money);
    }

    @Override
    public void withdraw(double money) {
        payInterest();
        userAccount.setBalance(userAccount.getBalance() - money);
    }

    @Override
    public void payInterest() {
        System.out.println("支付利息:" + userAccount.getBalance() * 0.01);
        userAccount.setBalance(userAccount.getBalance() * ( 1 + 0.01));
    }

    @Override
    public String getState() {
        return "透支";
    }
}

public class LimitationCardState extends CardState{

    public LimitationCardState(UserAccount userAccount) {
        super(userAccount);
    }

    @Override
    public void deposit(double money) {
        payInterest();
        userAccount.setBalance(userAccount.getBalance() + money);
    }

    @Override
    public void withdraw(double money) {
        System.out.println("该账户已受限,不能取款");
    }

    @Override
    public void payInterest() {
        System.out.println("支付利息:" + userAccount.getBalance() * 0.01);
        userAccount.setBalance(userAccount.getBalance() * ( 1 + 0.01));
    }

    @Override
    public String getState() {
        return "受限";
    }
}

使用状态模式后,在编码过程中,可以不要在关系具体状态,只需专注实现具体状态下的业务。

1.1 状态转换方式

在状态模式中,环境类的状态转换方式有两种:

1)在环境类完成转换。(上面代码是以这种形式)

2)在具体状态类中完成转换。

状态模式-对象状态及其转换,# 设计模式的艺术,状态模式,设计模式

图 两种状态转换方式的比较

如果新增状态类,则两种方式都需要在各自的类中做修改。都不符合开闭原则。

1.2 共享状态

在有些情况下,多个环境类对象需要共享一个状态,这时需要把状态对象定义为一个静态成员对象。

需求:一个房间有两个开关来控制灯泡的开关。开关等功能是固定的(打开只能使灯泡亮起,关闭只能使灯泡熄灭。

public class LightSwitch {

    private final static LightState onState = new OnLightState(),offState = new OffLightState();

    private static LightState lightState = offState;

    private final String name;

    public LightSwitch(String name) {
        this.name = name;
    }

    public static void changeLightState(String type) {
        if ("on".equalsIgnoreCase(type)) {
            lightState = onState;
        } else {
            lightState = offState;
        }
    }

    public void off() {
        System.out.println(name + "关闭操作");
        lightState.off(this);
    }

    public void on() {
        System.out.println(name + "打开操作");
        lightState.on(this);
    }

}

public abstract class LightState {

    public abstract void on(LightSwitch lightSwitch);

    public abstract void off(LightSwitch lightSwitch);
}

public class OnLightState extends LightState{

    @Override
    public void on(LightSwitch lightSwitch) {
        System.out.println("灯泡已打开");
        System.out.println("--------------");
    }

    @Override
    public void off(LightSwitch lightSwitch) {
        System.out.println("关闭成功");
        LightSwitch.changeLightState("off");
        System.out.println("--------------");
    }

}

public class OffLightState extends LightState{

    @Override
    public void on(LightSwitch lightSwitch) {
        System.out.println("打开成功");
        LightSwitch.changeLightState("on");
        System.out.println("--------------");
    }

    @Override
    public void off(LightSwitch lightSwitch) {
        System.out.println("灯泡已关闭");
        System.out.println("--------------");
    }

}

public class PeopleOpera {
    public static void main(String[] args) {
        LightSwitch lightSwitch1 = new LightSwitch("开关1");
        LightSwitch lightSwitch2 = new LightSwitch("开关2");

        lightSwitch1.on();
        lightSwitch2.off();
        lightSwitch1.off();
        lightSwitch1.on();
        lightSwitch2.on();
        lightSwitch2.off();
    }
}

//开关1打开操作
//打开成功
//--------------
//开关2关闭操作
//关闭成功
//--------------
//开关1关闭操作
//灯泡已关闭
//--------------
//开关1打开操作
//打开成功
//--------------
//开关2打开操作
//灯泡已打开
//--------------
//开关2关闭操作
//关闭成功
//--------------

2 优缺点

优点:

1)环境类转换状态方式,封装状态的转换规则,对状态转换代码集中管理。

2)将所有与具体状态有关的行为都封装在一个类中。

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

4)在具体状态类中转换状态方式,将状态转换逻辑与状态对象合成一起,避免使用庞大的条件语句块来将业务方法和状态转换代码交织在一起。

缺点:

1)增加了类和对象的个数。

2)实现较为复杂,增加了系统设计难度。

3)对开闭原则的支持并不好。

3 适用场景

1)对象的行为依赖它的状态,且状态之间互相转换。

2)代码中包含大量与对象状态有关的条件语句。文章来源地址https://www.toymoban.com/news/detail-715948.html

到了这里,关于状态模式-对象状态及其转换的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 《设计模式的艺术》笔记 - 装饰模式

            装饰模式动态地给一个对象增加一些额外的职责,就增加对象功能来说,装饰模式比生成子类实现更为灵活。装饰模式是一种对象结构型模式。  myclass.h myclass.cpp main.cpp         1. 对于扩展一个对象的功能,装饰模式比继承更加灵活性,不会导致类的个数急剧增加

    2024年01月19日
    浏览(44)
  • 《设计模式的艺术》笔记 - 外观模式

            外观模式中外部与一个子系统的通信通过一个统一的外观角色进行,为子系统中的一组接口提供一个一致的入口。外观模式定义了一个高层接口,这个接口使得子系统更加容易使用。外观模式又称为门面模式,它是一种对象结构型模式。 myclass.h myclass.cpp main.cpp    

    2024年01月19日
    浏览(42)
  • 《设计模式的艺术》笔记 - 策略模式

            策略模式定义一系列算法类,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化,也称为政策模式。策略模式是一种对象行为模式。 myclass.h myclass.cpp main.cpp         1. 策略模式提供了对开闭原则的完美支持。用户可以在不

    2024年01月25日
    浏览(37)
  • 《设计模式的艺术》笔记 - 组合模式

            组合模式组合多个对象形成树形结构以表示具有“部分-整体”关系的层次结构。组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性,又可以称为“部分—整体”(Part-Whole)模式,它是一种对象结构型模式。 myclass.h myclass.cpp main.cpp  

    2024年01月19日
    浏览(38)
  • 《设计模式的艺术》笔记 - 代理模式

            代理模式是给某一个对象提供一个代理,并由代理对象控制对原对象的引用。代理模式是一种对象结构型模式。 myclass.h myclass.cpp main.cpp         1. 代理模式能够协调调用者和被调用者,在一定程度上降低了系统的耦合度,满足迪米特法则。         2. 客户端可以

    2024年01月19日
    浏览(46)
  • 《设计模式的艺术》笔记 - 桥接模式

            桥接模式将抽象部分与其实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体模式或接口模式 myclass.h myclass.cpp main.cpp         1. 分离抽象接口及其实现部分。桥接模式使用“对象间的关联关系”解耦了抽象和实现之间固有的绑定关系,

    2024年01月18日
    浏览(45)
  • 《设计模式的艺术》笔记 - 命令模式

            命令模式将一个请求封装为一个对象,从而可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。命令模式是一种对象行为模式,其别名为动作模式或事务模式。 myclass.h myclass.cpp main.cpp         只需要增加一个CommandQueue类即可

    2024年01月20日
    浏览(44)
  • 《设计模式的艺术》笔记 - 迭代器模式

            迭代器模式提供一种方法来访问聚合对象,而不用暴露这个对象的内部表示,其别名为游标(Cursor)。迭代器模式是一种对象行为型模式。 myclass.h myclass.cpp main.cpp         1. 支持以不同的方式遍历一个聚合对象,在同一个聚合对象上可以定义多种遍历方式。在迭代

    2024年01月24日
    浏览(39)
  • 《设计模式的艺术》笔记 - 享元模式

            享元模式运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式,是一种对象结构型模式。 myclass.

    2024年01月19日
    浏览(32)
  • 《设计模式的艺术》笔记 - 单例模式

            单例模式优点是可以确保系统中只存在单个对象实例,缺点是不便扩展,一定程度上违背单一原则,既提供业务方法,又提供创建对象方法         在类加载的时候就创建好对象,获取对象时直接返回即可         在类加载的时候没有创建对象,第一次获取对象

    2024年02月02日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包