设计模式浅析(十一) ·状态模式

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

设计模式浅析(十一) ·状态模式

日常叨逼叨

java设计模式浅析,如果觉得对你有帮助,记得一键三连,谢谢各位观众老爷😁😁


状态模式

概念

状态模式

Java中的状态模式(State Pattern)是一种行为型设计模式,它允许一个对象在其内部状态改变时改变它的行为,看起来就像修改了它的类一样。状态模式的核心在于将状态与行为绑定,不同的状态对应不同的行为。

举个🌰

假设自动贩卖机只贩卖白水这一种商品,自动贩卖机的设计师为我们提供了一张状态图,希望我们设计程序供他们的机器使用,我们先来看一下

设计模式浅析(十一) ·状态模式,java 设计模式,设计模式

经过一番研究,我们可以看得出,上述的状态转化图,我们可以试着将其转化为代码

首先,列出所有的状态

白水售罄售出白水有1.5元没有1.5元

然后定义一些表示状态的变量

final static Integer SOLD_OUT=0;
final static Integer NO_MONEY_1_5=1;
final static Integer HAS_MONEY_1_5=2;
final static Integer SOLD=3;

将整个售卖过程整合起来,对于售卖机器而言

 public void insertMoney() {
        if (state == HAS_MONEY_1_5) {
            //...
            System.out.println("you can't insert money ");
        } else if (state == SOLD_OUT) {
            //...
            System.out.println("you can't insert money , the machine is sold out");
        } else if (state == SOLD) {
            //...
            System.out.println("please wait, we give you a bottom of water");
        } else if (state == NO_MONEY_1_5) {
            state = HAS_MONEY_1_5;
            System.out.println("you inserted money");
        }
    }

接着上面的逻辑,我们实现整个自动化的白水贩卖机

package com.jerry.statepattern;

/**
 * @version 1.0
 * @Author jerryLau
 * @Date 2024/4/7 16:08
 * @注释 自动售卖机
 */
public class VendingMachines {
    final static Integer SOLD_OUT = 0;
    final static Integer NO_MONEY_1_5 = 1;
    final static Integer HAS_MONEY_1_5 = 2;
    final static Integer SOLD = 3;

    int state = SOLD_OUT;
    int count = 0;

    public VendingMachines(int count) {
        this.count = count;
        if (count > 0) {
            state = NO_MONEY_1_5;
        }
    }

    /***
     * 投币
     */
    public void insertMoney() {
        if (state == HAS_MONEY_1_5) {
            System.out.println("you can't insert money ");
        } else if (state == SOLD_OUT) {
            System.out.println("you can't insert money , the machine is sold out");
        } else if (state == SOLD) {
            System.out.println("please wait, we give you a bottom of water");
        } else if (state == NO_MONEY_1_5) {
            state = HAS_MONEY_1_5;
            System.out.println("you inserted money");
        }
    }

    /***
     * 退币
     */
    public void ReturnMoney() {
        if (state == HAS_MONEY_1_5) {
            System.out.println("money returned");
            state = NO_MONEY_1_5;
        } else if (state == SOLD_OUT) {
            System.out.println("you can't return,you have not  insert money yet ");
        } else if (state == SOLD) {
            System.out.println("you already passed the button");
        } else if (state == NO_MONEY_1_5) {
            System.out.println("you have not  insert money");
        }
    }


    /***
     * 按钮按下
     */
    public void passButton() {
        if (state == HAS_MONEY_1_5) {
            System.out.println("you passed the button ...");
            state = SOLD;
            //发放水
            distribute();
        } else if (state == SOLD_OUT) {
            System.out.println("you passed the button,but no water sold ");
        } else if (state == SOLD) {
            System.out.println("pass button twice doesn't get another water");
        } else if (state == NO_MONEY_1_5) {
            System.out.println("you passed the button,but you should insert money first");
        }

    }

    /***
     * 分发水
     */
    public void distribute() {
        if (state == SOLD) {
            System.out.println("A bottom of water comes rolling out the slot");
            count = count - 1;
            if (count == 0) {
                System.out.println("Oops,out of water!");
                state = SOLD_OUT;
            } else {
                state = NO_MONEY_1_5;
            }
        } else if (state == NO_MONEY_1_5) {
            System.out.println("You need to pay first");
        } else if (state == SOLD_OUT) {
            System.out.println("No water distributed");
        } else if (state == HAS_MONEY_1_5) {
            System.out.println("No water distributed");
        }

    }
    //....

    @Override
    public String toString() {
        return "VendingMachines{" +
                "state=" + state +
                ", count=" + count +
                '}';
    }
}

准备测试类

package com.jerry.statepattern;

/**
 * @version 1.0
 * @Author jerryLau
 * @Date 2024/4/7 16:09
 * @注释  VendingMachines 测试
 */
public class VendingMachinesTestMain {

    public static void main(String[] args) {
        VendingMachines gumballMachine = new VendingMachines(5);

        System.out.println(gumballMachine);

        gumballMachine.insertMoney();
        gumballMachine.passButton();
        System.out.println(gumballMachine);

        gumballMachine.insertMoney();
        gumballMachine.ReturnMoney();
        gumballMachine.passButton();
        System.out.println(gumballMachine);
//
//
        gumballMachine.insertMoney();
        gumballMachine.passButton();
        gumballMachine.insertMoney();
        gumballMachine.passButton();
        gumballMachine.ReturnMoney();
        System.out.println(gumballMachine);
//
        gumballMachine.insertMoney();
        gumballMachine.insertMoney();
        gumballMachine.passButton();
        gumballMachine.insertMoney();
        gumballMachine.passButton();
        gumballMachine.insertMoney();
        gumballMachine.passButton();
        System.out.println(gumballMachine);

    }
}

运行结果

VendingMachines{state=1, count=5}
you inserted money
you passed the button …
A bottom of water comes rolling out the slot
VendingMachines{state=1, count=4}
you inserted money
money returned
you passed the button,but you should insert money first
VendingMachines{state=1, count=4}
you inserted money
you passed the button …
A bottom of water comes rolling out the slot
you inserted money
you passed the button …
A bottom of water comes rolling out the slot
you have not insert money
VendingMachines{state=1, count=2}
you inserted money
you can’t insert money
you passed the button …
A bottom of water comes rolling out the slot
you inserted money
you passed the button …
A bottom of water comes rolling out the slot
Oops,out of water!
you can’t insert money , the machine is sold out
you passed the button,but no water sold
VendingMachines{state=0, count=0}

Process finished with exit code 0

感觉好像没什么太大的问题,我们将代码提交给自动贩卖机的老板,他们再运行后觉得非常完美,但就是太过完美了,他们想玩点花的,提出了下面的需求:

当用户投币后按下按钮后,有10%的几率掉下来的是两瓶水(多送你一瓶),这将大大加大销售量

对于他们提出的需求,emmm大概想了想,在现有代码中修改的地方比较多

  • 加一个状态
  • 对于每个步骤都得进行添加新状态的判断
  • 对于按下按钮这一方法里面的内容进行大量的修改

如果采用在现在代码上进行修改,会存在以下几种问题

  • 这份代码确实没有遵守开放-关闲原则。
  • 这个设计其实不符合面向对象。
  • 状态转换被埋藏在条件语句中,所以不明显。
  • 我们还没有把会改变的那部分包装来。
  • 未来加人的代码很有可能会导致bug。

考虑到可能会出现以上的问题,我们决定做如下新的设计

我们的计划是这样的:不要维护我们现有的代码,我们重写它以便于将状态对象封装在各自的类中,然后在动作发生时委托给当前状态。

我们在这里遵照我们的设计原则,所以最后应该得到一个容易维护的设计。

我们要做的事情是:

  • 首先,我们定义一个State接口。在这个接口内,贩卖机的每个动作都有一个对应的方法。
  • 然后为机器中的每个状态实现状态类。这些类将负责在对应的状态下进行机器的行为。
  • 最后,我们要摆脱旧的条件代码,取而代之的方式是,将动作委托到状态类。

你将会看到,我们不仅遵守了设计原则,实际上我们还实现了状态模式。在重新完成代码之后我们再来了解状态模式的正式定义…

设计模式浅析(十一) ·状态模式,java 设计模式,设计模式

package com.jerry.statepattern.newDisign;

/**
 * @version 1.0
 * @Author jerryLau
 * @Date 2024/4/8 8:42
 * @注释 新的状态的额接口
 */
public interface State {
    /***
     * 投币
     */
    public void insertMoney();

    /***
     * 退币
     */
    public void returnMoney() ;

    /***
     * 按钮按下
     */
    public void passButton() ;

    /***
     * 分发水
     */
    public void distribute() ;
}

状态有点多,我们简单的列举一二

package com.jerry.statepattern.newDisign;

/**
 * @version 1.0
 * @Author jerryLau
 * @Date 2024/4/8 8:45
 * @注释 没有被投币的状态
 */
public class No1_5State implements  State{
    NewVendingMachines newVendingMachines;

    public No1_5State(NewVendingMachines newVendingMachines) {
        this.newVendingMachines = newVendingMachines;
    }

    @Override
    public void insertMoney() {
        System.out.println("you insert money");
        newVendingMachines.setState(newVendingMachines.getHas1_5State());
    }

    @Override
    public void returnMoney() {
        System.out.println("you aren't insert money");
    }

    @Override
    public void passButton() {
        System.out.println("you passed Button,but no water gives to you cause you aren't insert money");
    }

    @Override
    public void distribute() {
        System.out.println("you need to pay first");
    }
}

package com.jerry.statepattern.newDisign;

/**
 * @version 1.0
 * @Author jerryLau
 * @Date 2024/4/8 8:44
 * @注释 售出状态
 */
public class SoldState implements State {
    NewVendingMachines newVendingMachines;

    public SoldState(NewVendingMachines newVendingMachines) {
        this.newVendingMachines = newVendingMachines;
    }

    @Override
    public void insertMoney() {
        System.out.println("please wait a moment ,we will give you a bottom of water");
    }

    @Override
    public void returnMoney() {
        System.out.println("no money returned cause you have passed the button");
    }

    @Override
    public void passButton() {
        System.out.println("passed the button twice doesn't give another water ");
    }

    @Override
    public void distribute() {
        newVendingMachines.flushWater();
        if (newVendingMachines.getCount() > 0) {
            newVendingMachines.setState(newVendingMachines.getNo1_5State());
        } else {
            newVendingMachines.setState(newVendingMachines.getSoldOutState());
        }
    }
}

添加上赢家的状态

package com.jerry.statepattern.newDisign;

/**
 * @version 1.0
 * @Author jerryLau
 * @Date 2024/4/8 8:46
 * @注释 产生赢家状态
 */
public class WinnerState implements State {
    NewVendingMachines newVendingMachines;

    public WinnerState(NewVendingMachines newVendingMachines) {
        this.newVendingMachines = newVendingMachines;
    }

    @Override
    public void insertMoney() {
        System.out.println("no need to insert money");
    }

    @Override
    public void returnMoney() {
        System.out.println("no money return");
    }

    @Override
    public void passButton() {
        System.out.println("you passed money but no water gives to you ");
    }

    @Override
    public void distribute() {
        System.out.println("YOU'RE a WINNER! You get another water ");
        newVendingMachines.flushWater();
        if (newVendingMachines.getCount() == 0) {
            newVendingMachines.setState(newVendingMachines.getSoldOutState());
        } else {
            newVendingMachines.flushWater();
            if (newVendingMachines.getCount() > 0) {
                newVendingMachines.setState(newVendingMachines.getNo1_5State());
            } else {
                System.out.println("Oops,out of water!");
                newVendingMachines.setState(newVendingMachines.getSoldOutState());
            }
        }
    }
}

那么持有1.5元状态(投币状态)代码就会在进行响应的修改

package com.jerry.statepattern.newDisign;

/**
 * @version 1.0
 * @Author jerryLau
 * @Date 2024/4/8 8:45
 * @注释 被投币状态
 */
public class Has1_5State implements State {
    NewVendingMachines newVendingMachines;

    public Has1_5State(NewVendingMachines newVendingMachines) {
        this.newVendingMachines = newVendingMachines;
    }

    @Override
    public void insertMoney() {
        System.out.println("you have insert money, no more money need insert");
    }

    @Override
    public void returnMoney() {
        System.out.println("money returned");
        newVendingMachines.setState(newVendingMachines.getNo1_5State());
    }

    @Override
    public void passButton() {
        System.out.println("you passed the button...");

        int winner = (int)(Math.random()*10);
        if ((winner == 0) && (newVendingMachines.getCount() > 1)) {
            newVendingMachines.setState(newVendingMachines.getWinnerState());
        } else {
            newVendingMachines.setState(newVendingMachines.getSoldState());
        }
    }

    @Override
    public void distribute() {
        System.out.println("no water distributed");
    }
}

此外呢,贩卖机也做如下修改

package com.jerry.statepattern.newDisign;

/**
 * @version 1.0
 * @Author jerryLau
 * @Date 2024/4/7 16:08
 * @注释 自动售卖机
 */
public class NewVendingMachines {
    State soldState;
    State soldOutState;
    State has1_5State;
    State no1_5State;

    State winnerState;

    State state = soldOutState;
    int count = 0;

    public NewVendingMachines(int count) {

        soldState = new SoldState(this);
        soldOutState = new SoldOutState(this);
        has1_5State = new Has1_5State(this);
        no1_5State = new No1_5State(this);
        winnerState = new WinnerState(this);
        this.count = count;
        if (count > 0) {
            state = no1_5State;
        }
    }

    public void insertMoney() {
        state.insertMoney();
    }

    /***
     * 退币
     */
    public void returnMoney() {
        state.returnMoney();
    }


    /***
     * 按钮按下
     */
    public void passButton() {
        state.passButton();
        state.distribute();
    }

    public void setState(State state) {
        this.state = state;
    }


    public void flushWater() {
        System.out.println("A bottom of water comes rolling out the slot");
        if (count != 0) {
            count = count-1;
        }
    }

    public State getSoldState() {
        return soldState;
    }

    public State getSoldOutState() {
        return soldOutState;
    }

    public State getHas1_5State() {
        return has1_5State;
    }

    public State getNo1_5State() {
        return no1_5State;
    }

    public State getState() {
        return state;
    }

    public State getWinnerState() {
        return winnerState;
    }

    public int getCount() {
        return count;
    }

    //....

    @Override
    public String toString() {
        return "VendingMachines{" +
                "state=" + state +
                ", count=" + count +
                '}';
    }
}

构建本地测试类

public class TestMainDriver {
    public static void main(String[] args) {
        NewVendingMachines gumballMachine = new NewVendingMachines(5);
        System.out.println(gumballMachine);
        gumballMachine.insertMoney();
        gumballMachine.passButton();
        System.out.println(gumballMachine);

    }
}

运行结果

VendingMachines{state=com.jerry.statepattern.newDisign.No1_5State@1b6d3586, count=5}
you insert money
you passed the button…
A bottom of water comes rolling out the slot
VendingMachines{state=com.jerry.statepattern.newDisign.No1_5State@1b6d3586, count=4}

Process finished with exit code 0

很明显哈,我不是一个幸运的人,哈哈哈

至此我们完成了无知老板的需求,也实现了状态设计模式。

我们再次来回顾一下,在上述过程中我们做了些什么

状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。

这个描述中的第一部分附有相当多的涵义,是吧?因为这个模式将状态封装成为独立的类,并将动作委托到代表当前状态的对象,我们知道行为会随着内部状态而改变。贩卖机提供了一个很好的例子,当贩卖机是在未投币或已投币两种不同的状态时,你投入1.5元钱,就会得到不同的行为(机器接受1.5元和机器拒绝1.5元)。

而这个定义中的第二部分呢?一个对象“看起来好像修改了它的类”是什么意思呢?从客户的视角来看:如果说你使用的对象能够完全改变它的行为,那么你会觉得,这个对象实际上是从别的类实例化而来的。然而,实际上,你知道我们是在使用组合通过简单引用不同的状态对象来造成类改变的假象。

状态模式的类图

设计模式浅析(十一) ·状态模式,java 设计模式,设计模式

新需求中,我们补全状态转化图

设计模式浅析(十一) ·状态模式,java 设计模式,设计模式

优缺点

优点:
  1. 封装了转换规则:将状态的转换规则分散到多个状态类中,减少了相互之间的依赖。
  2. 易于维护:把状态的判断逻辑转移到了表示不同状态的一系列类中,可以把复杂的判断逻辑简化。
  3. 将行为局部化:每一个状态对应一个子类,而将请求委托给当前状态对象自行处理。
缺点:
  1. 状态过多导致类膨胀:如果状态过多,会造成类个数过多,系统变得庞大。
  2. 设计难度和复杂度:对于可以切换状态的状态机,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。

代码相关代码可以参考 gitee代码仓库🌐 || github🤖

ps:本文原创,转载请注明出处文章来源地址https://www.toymoban.com/news/detail-848823.html


到了这里,关于设计模式浅析(十一) ·状态模式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 【设计模式】用Java实现状态模式

    状态模式是一种行为设计模式,它允许对象在内部状态发生改变时改变其行为。该模式将对象的行为包装在不同的状态类中,使得对象的行为可以根据其当前状态动态改变。 状态模式通常由以下几个角色组成: 环境类(Context) :环境类是拥有状态的对象,它将会根据当前状

    2024年02月10日
    浏览(32)
  • 【十五】设计模式~~~行为型模式~~~状态模式(Java)

    【学习难度:★★★☆☆,使用频率:★★★☆☆】 在很多情况下,一个对象的行为取决于一个或多个动态变化的属性,这样的属性叫做状态,这样的对象叫做有状态的(stateful)对象,这样的对象状态是从事先定义好的一系列值中取出的。当一个这样的对象与外部事件产生互

    2024年02月07日
    浏览(49)
  • 【Java 设计模式】行为型之状态模式

    状态模式(State Pattern)是一种行为型设计模式,用于通过将对象的行为封装到不同的状态类中,使得对象在不同的状态下具有不同的行为。状态模式允许对象在内部状态发生改变时改变其行为,而无需修改其代码。在本文中,我们将深入研究Java中状态模式的定义、结构、使

    2024年01月24日
    浏览(51)
  • Java设计模式之行为型-状态模式(UML类图+案例分析)

    目录 一、基础概念 二、UML类图 三、角色设计 四、案例分析 五、总结 状态模式允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类,状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况,把状态的判断逻辑转移到表示不

    2024年02月16日
    浏览(40)
  • 【设计模式——学习笔记】23种设计模式——状态模式State(原理讲解+应用场景介绍+案例介绍+Java代码实现)

    请编写程序完成APP抽奖活动具体要求如下: 假如每参加一次这个活动要扣除用户50积分,中奖概率是10% 奖品数量固定,抽完就不能抽奖 活动有四个状态: 可以抽奖、不能抽奖、发放奖品和奖品领完,活动的四个状态转换关系图如下 一开始的状态为“不能抽奖”,当扣除50积分

    2024年02月12日
    浏览(49)
  • 设计模式浅析(十) ·设计模式之迭代器&组合模式

    日常叨逼叨 java设计模式浅析,如果觉得对你有帮助,记得一键三连,谢谢各位观众老爷😁😁 案例 有两家门店,门店A呢只提供早餐,门店B呢只提供午餐,有一天这两家店铺想要进行合并,一起做大做强,再创辉煌。 合并后呢,对于菜单的定制存在了一定的问题: 门店A的

    2024年04月11日
    浏览(48)
  • 设计模式浅析

    设计模式(Design Patterns)是在软件开发中经过验证的最佳实践,用于解决常见的设计问题。它们提供了一种可复用的解决方案,可以帮助开发人员提高代码质量、可维护性和可重用性。设计模式的采用通常在以下情况下被考虑: 1.代码重用性:当您发现多个地方有相似的代码

    2024年02月22日
    浏览(31)
  • 浅析五种 React 组件设计模式

    作为一名 React 开发者,你可能会面临下面几个问题: 如何构建一个高复用度性的组件,使其适应不同的业务场景? 如何构建一个具有简单 API的组件,使其易于使用? 如何构建一个在 UI 和功能方面具有可扩展性的组件? 为解决上述问题,下面介绍五种 React 组件设计模式,

    2024年02月02日
    浏览(38)
  • 设计模式详解(十一)——组合模式

    组合模式定义 组合模式(Composite Pattern)是一种结构型设计模式,又叫部分整体模式,它将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。

    2024年02月22日
    浏览(39)
  • 软件设计模式系列之十一——装饰模式

    当谈到设计软件系统时,经常需要考虑如何使系统更加灵活、可扩展和易维护。设计模式是一种被广泛采用的方法,用于解决常见的设计问题,并提供了一套可重用的解决方案。装饰模式(Decorator Pattern)是一种结构型设计模式,它允许您在不改变对象接口的情况下动态地添

    2024年02月08日
    浏览(44)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包