状态模式(State Pattern)

状态模式 State Pattern 作者:禅与计算机程序设计艺术 1.简介 在面向对象编程中,状态模式是一种行为设计模式,它可以帮助我们管理对象的状态变化。它把对象的状态封装到一个类中,并通过该类的行为来改变对象状态。这种方式使得对象内在的复杂状态变化变得可控、方便追踪,也可实现不同状态之间的转移。状态模式应用很广泛,比如,计算机系统中的 阅读详情

抽奖问题

 1.每参加一次抽奖需要50积分,中奖概率10%

 2.奖品数量有限,没有即止

 3.抽象由4个状态:可以抽奖、不能抽奖、发放奖品、奖品领完。

 

状态模式

 状态模式:它主要用来解决对象在多种状态转换时,需要对外输出不同的行为的问题。状态和行为是一一对应的,状态之间可以相互转换

 当一个对象的内在状态改变时,允许改变其行为,这个对象看起来像是改变了其类

 

状态模式结构

在这里插入图片描述

 1.上下文 (Context) 保存了对于一个具体状态对象的引用, 并会将所有与该状态相关的工作委派给它。 上下文通过状态接口与状态对象交互, 且会提供一个设置器用于传递新的状态对象。

 2.状态 (State) 接口会声明特定于状态的方法。 这些方法应能被其他所有具体状态所理解, 因为你不希望某些状态所拥有的方法永远不会被调用。

 3.具体状态 (Concrete States) 会自行实现特定于状态的方法。 为了避免多个状态中包含相似代码, 你可以提供一个封装有部分通用行为的中间抽象类。

 状态对象可存储对于上下文对象的反向引用。 状态可以通过该引用从上下文处获取所需信息, 并且能触发状态转移。

上下文和具体状态都可以设置上下文的下个状态, 并可通过替换连接到上下文的状态对象来完成实际的状态转换。

 

状态模式适合应用场景

 1.如果对象需要根据自身当前状态进行不同行为, 同时状态的数量非常多且与状态相关的代码会频繁变更的话, 可使用状态模式。

 2.如果某个类需要根据成员变量的当前值改变自身行为, 从而需要使用大量的条件语句时, 可使用该模式。

 3.当相似状态和基于条件的状态机转换中存在许多重复代码时, 可使用状态模式。

 

实现方式

  1. 确定哪些类是上下文。 它可能是包含依赖于状态的代码的已有类; 如果特定于状态的代码分散在多个类中, 那么它可能是一个新的类。

  2. 声明状态接口。 虽然你可能会需要完全复制上下文中声明的所有方法, 但最好是仅把关注点放在那些可能包含特定于状态的行为的方法上。

  3. 为每个实际状态创建一个继承于状态接口的类。 然后检查上下文中的方法并将与特定状态相关的所有代码抽取到新建的类中。

    在将代码移动到状态类的过程中, 你可能会发现它依赖于上下文中的一些私有成员。 你可以采用以下几种变通方式:

    • 将这些成员变量或方法设为公有。
    • 将需要抽取的上下文行为更改为上下文中的公有方法, 然后在状态类中调用。 这种方式简陋却便捷, 你可以稍后再对其进行修补。
    • 将状态类嵌套在上下文类中。 这种方式需要你所使用的编程语言支持嵌套类。
  4. 在上下文类中添加一个状态接口类型的引用成员变量, 以及一个用于修改该成员变量值的公有设置器。

  5. 再次检查上下文中的方法, 将空的条件语句替换为相应的状态对象方法。

  6. 为切换上下文状态, 你需要创建某个状态类实例并将其传递给上下文。 你可以在上下文、 各种状态或客户端中完成这项工作。 无论在何处完成这项工作, 该类都将依赖于其所实例化的具体类。

 

状态模式优缺点

 优点:

  ✔️单一职责原则。 将与特定状态相关的代码放在单独的类中。

  ✔️开闭原则。 无需修改已有状态类和上下文就能引入新状态。

  ✔️通过消除臃肿的状态机条件语句简化上下文代码。

 缺点:

  ❌如果状态机只有很少的几个状态, 或者很少发生改变, 那么应用该模式可能会显得小题大作。

 

解决抽奖问题

在这里插入图片描述

代码:

​

//抽奖活动
public class Activity {
    //当前状态
    State state = null;
    //奖品数量
    int count = 0;

    //四个状态
    State noRaffleState = new NoRaffleState(this);
    State canRaffleState =new CanRaffleState(this);
    State dispenseState =new DispenseState(this);
    State dispenseOutState =new DispenseOutState(this);

    //默认为 不可抽奖、并定义奖品数量
    public Activity(int count){
        this.state = getNoRaffleState();
        this.count = count;
    }

    //扣除积分
    public void deductMoney(){
        state.deductMoney();
    }

    //抽奖
    public void raffle(){
        //抽奖成功则领取奖品
        if (state.raffle()){
            state.dispensePrize();
        }
    }

    //此处,每获取一次奖品,则count--
    public int getCount() {
        int afterCount = count;
        count--;
        return afterCount;
    }

	//get&set方法
   
}
public abstract class State {
    //抽奖条件:-50积分
    public abstract void deductMoney();

    //是否抽中商品
    public abstract boolean raffle();

    //发奖品
    public abstract void dispensePrize();
}
//不能抽奖
public class NoRaffleState extends State {
    Activity activity;

    public NoRaffleState(Activity activity) {
        this.activity = activity;
    }

    //扣除机会后,需要更改成可抽奖状态
    @Override
    public void deductMoney() {
        System.out.println("扣除50积分,可抽奖");
        activity.setState(activity.getCanRaffleState());
    }

    //当前状态不可抽奖
    @Override
    public boolean raffle() {
        System.out.println("扣了积分才可抽奖");
        return false;
    }

    //当前状态不能发奖品
    @Override
    public void dispensePrize() {
        System.out.println("当前状态不能发奖品");
    }
}

//可抽奖
public class CanRaffleState extends State{

    Activity activity;

    public CanRaffleState(Activity activity) {
        this.activity = activity;
    }

    //已经扣过积分了
    @Override
    public void deductMoney() {
        System.out.println("已扣积分。");
    }

    //可抽奖,抽完后需要更改状态
    @Override
    public boolean raffle() {
        System.out.println("正在抽奖");

        int num = new Random().nextInt(10);

        if (num == 0){
            //num = 0 则抽中了奖,发奖品
            activity.setState(activity.getDispenseState());
            return true;
        }else {
            //未抽中奖品
            System.out.println("很遗憾未抽到奖品");
            activity.setState(activity.getNoRaffleState());
            return false;
        }
    }

    @Override
    public void dispensePrize() {
        System.out.println("很遗憾,未抽中");
    }
}

//发放奖品
public class DispenseState extends State{

    Activity activity;

    public DispenseState(Activity activity) {
        this.activity = activity;
    }

    @Override
    public void deductMoney() {
        System.out.println("发奖品,不扣积分");
    }

    @Override
    public boolean raffle() {
        System.out.println("不能抽奖");
        return false;
    }

    @Override
    public void dispensePrize() {
        if (activity.getCount()>0){
            System.out.println("恭喜中奖了");
            //状态改变 不能抽奖
            activity.setState(activity.getNoRaffleState());
        }else {
            System.out.println("奖品已发完");
            //状态改变 不能抽奖
            activity.setState(activity.getDispenseOutState());
        }
    }
}

//奖品发完状态
public class DispenseOutState extends State {

    //初始化时,传入活动引用
    Activity activity;

    public DispenseOutState(Activity activity) {
        this.activity = activity;
    }

    @Override
    public void deductMoney() {
        System.out.println("奖品已发完,请下次再来");
    }

    @Override
    public boolean raffle() {
        System.out.println("奖品已发完,请下次再来");
        return false;
    }

    @Override
    public void dispensePrize() {
        System.out.println("奖品已发完,请下次再来");
    }
}
public class Client {
    public static void main(String[] args) {
        //定义有20个奖品的活动
        Activity activity = new Activity(20);

        //遍历30次
        for (int i = 1; i <= 30; i++) {
            System.out.println("第"+i+"次");
            //先扣分后抽奖
            activity.deductMoney();
            activity.raffle();
        }
    }
}

状态模式的注意事项和细节
 1.代码有很强的可读性。状态模式将每个状态的行为封装到对应的一个类中

 2.方便维护。将容易产生问题的 if else 语句删除了,如果把每个状态的行为都放到一个类中,每次调用方法时都要判断当前是什么状态,不但会产出很多 if else 语句,而且容易出错

 3.符合“开闭原则”。容易增删状态

 4.会产生很多类。每个状态都要一个对应的类,当状态过多时会产生很多类,加大维护难度

 5.应用场景:当 一个事件或者对象有很多种状态,状态之间会相互转换,对不同的状态要求有不同的行为的时 候,可以考虑使用状态模式

状态模式(State Pattern)详解 状态模式是一种行为设计模式,它允许对象在内部状态改变时改变它的行为。这种模式将状态相关的行为抽取到独立的状态类中,使得代码更加清晰、可维护,并且可以在运行时自由切换对象的状态。在状态模式中,我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的上下文对象。消除了复杂的条件分支语句提高了代码的可维护性和可扩展性使状态转换更加明确,减少了出错可能符合开闭原则,便于添加新状态。 阅读详情

相关推荐

状态模式代码

设计模式中状态模式例子,使用C++编写。在状态模式(State Pattern)中,类的行为是基于它的状态改变的。这种类型的设计模式属于行为型模式。 在状态模式中,我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context 对象。

设计模式24:State Pattern (状态模式)

英文原文:http://www.dofactory.com/Patterns/PatternState.aspx一、State Pattern (状态模式)Define: Allow an object to alter its behavior when its internal state changes. The object will appear to change its cl

薛敬明的专栏 1897

稳健自适应波束形成学习(2):自适应计算对角加载量方法——基于广义线性组合的鲁棒Capon波束形成

对于快拍数相对阵元数较小时,样本协方差矩阵不能很好对协方差矩阵进行估计。常规的对角加载量需要根据经验值或不断手动调整进行测试,没有一个明确的准则和推导。该篇介绍一种自适应计算对角加载量的方法,且能适应快拍数相对阵元数较小时的情况。均匀线阵阵元数:18;载波频率30MHz;通信信号来波方向0°、来波估计偏差0.5°;干扰来波方向30°;通信信号信噪比10dB;干扰信号信噪比60dB。也即在干扰角度生成66dB的零陷,通信信号受到16dB的衰减。

a1uajug的博客 825

状态模式(State Pattern)

也称为状态机模式(State Machine Pattern)通过定义不同的状态类来封装与特定状态相关的行为,并将状态的判断逻辑转移到表示不同状态的一系列类中,从而把复杂的判断逻辑简化。状态模式将状态和行为分开,使对象在内部状态改变时能够改变它的行为。每一个状态对应一个子类,从而将状态的转换逻辑分布到状态子类中,减少了相互依赖。客户端通常不直接与状态对象交互,而是通过环境类(Context)与状态对象进行交互。

yuiezt的专栏 677

搭建微信机器人的方案都在这了!

功能超级强大,虽不支持二次开发,但已有的功能足够个人使用,可惜官方作品已被腾讯告死,好在市面上还流落着不少破解版,有需要的自行搜索。可惜的是,微信官方已不准许新的微信号再使用 web 登录,这就直接从源头扼杀了 web 协议的微信机器人,虽说老的微信号还是能凑合着用,不过部分功能也受限。所以,这些都属于 PC 端的微信机器人。无论是 PC 端还是手机端,用 hook 方式实现的最大缺点就是要和某一个版本的微信客户端进行绑定,如果框架本身不对最新版本的微信适配,那使用的时候就无法升级到最新版本的微信。

weixin_47246330的博客 1万+

NuPlayer 之 Renderer

触发postDrainAudioQueue_l()或postDrainVideoQueue()开始渲染。解码器输出数据 → NuPlayer::Decoder::onMessageReceived。音频数据存入mAudioQueue,视频数据存入mVideoQueue。• 每次写入后通过mNotifyConsumed通知解码器。• 通过AudioSink::write()写入音频设备。• 根据VSync信号和音频时钟调整渲染时机。• 通过Surface直接提交给显示系统。

aningxiaoxixi的博客 310

状态模式-State Pattern

在软件开发过程中,应用程序中的有些对象可能会根据不同的情况做出不同的行为,我们把这种对象称为有状态的对象,而把影响对象行为的一个或多个动态变化的属性称为状态。当有状态的对象与外部事件产生互动时,其内部状态会发生改变,从而使得其行为也随之发生改变。如人的情绪有高兴的时候和伤心的时候,不同的情绪有不同的行为,当然外界也会影响其情绪变化。 对这种有状态的对象编程,传统的解决方案是:将这些所有可能发生的...

心猿意碼 4163

PX4/ArduPilot源码克隆提速秘籍:国内镜像与子模块优化全攻略

本文详细介绍了PX4/ArduPilot源码克隆的提速秘籍,包括使用国内镜像源和子模块优化技巧。通过阿木实验室、华为云等国内镜像,克隆速度可提升20倍,同时提供子模块替换和并行编译等实用方法,大幅提升开发效率。

weixin_29251567的博客 524

设计模式 状态模式(State Pattern)

状态模式(State Pattern)flyfish#include "stdafx.h" #include class role; class employee { public: virtual void output(role *role_ptr) = 0;};class engineer : public employee {public: virtua

二分掌柜的 838

【RTOS】 Vxworks 653 第一章 —— 初识 vx653 3.x

。。不是很重要,自己搜吧鲁棒分区是一种确保共享计算资源中独立运行功能实现​​时空隔离​​的机制,其目标是为集成模块中的混合临界性应用提供与联邦式部署(federated implementation)同等级别的功能隔离保障。具体表现为:​​多关键性共存​​:支持不同安全等级应用(如飞控系统A级与娱乐系统D级)在同一模块中协同运行。​​抗干扰能力​​:防止未授权或意外的时空干扰(如内存越界、时间窗口冲突),确保应用间互不影响。​​。

qq_38183694的博客 1280

Calibre LVS 问题解析

LVS常见问题与解决办法

m0_61544122的博客 2万+

java state用法博客园_状态模式-State Pattern(Java实现)

状态模式-State Pattern在状态模式(StatePattern)中,类的行为是基于它的状态改变的。当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。State接口表明状态, 实体类是根据状态的变化而发生响应行为的变化的./*** 状态抽象定义*/public interface State {void onEnterState();void observe();}...

weixin_29137997的博客 206

【人工智能】全面盘点国内AI九大模型:各擅胜场的智能先锋(豆包、文心一言、讯飞星火、通义千问、Kimi、智谱清言、腾讯元宝、秘塔、天工AI)

追求性价比与全能:选豆包,适合个人与中小企业日常使用;侧重中文创作与理解:选文心一言,文学与商业文案创作首选;需要专业语音交互:选讯飞星火,智能客服、车载场景必备;看重生态与多场景:选通义千问,适配电商、办公等企业需求;处理超长文本任务:选Kimi,文档分析、学术研究的利器;专注深度推理创作:选智谱清言,学术与创意写作的伙伴;依赖腾讯生态协同:选腾讯元宝,日常轻量需求的便捷之选;深耕法律学术领域:选秘塔,专业文本处理的权威工具;布局前沿技术体验:选天工AI,享受接近国际顶尖的智能服务。

奶爸的编程之路,也就一周冷个三天 1121

State Pattern 状态模式

State Pattern: allows an object to alter its behavior when its internal state changes. The object will appear to changes its class. Encapsulate state into separate classes. With the State Pattern, we

Geurney的专栏 597

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

状态模式State Pattern

状态模式(State Pattern)是一种对象行为型模式,它主要解决的是一个对象在其内部状态发生改变时会导致其行为的变化,通过将状态封装成独立的对象,可以使得状态的变化独立于对象的行为,从而实现状态和行为之间的解耦。状态模式通常包含以下角色:Context(上下文):定义客户端感兴趣的接口,维护一个对具体状态类的实例,以便于客户端调用具体状态类的方法。State(抽象状态):定义一个接口以封装与Context的一个特定状态相关的行为。ConcreteState(具体状态):实现State接口。

qq_34893654的博客 215

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

【状态模式】 State Pattern

我们先设计一个场景,饮料自动售卖机,来设计一下它的出售流程。 流程图中,我们可把这个过程看成几个状态: 投币状态,选择饮料状态,售出状态,出售完毕状态. ,有了这个四个状态,我们设计一下界面(很粗略): 在这里我们只定义了三种饮料和一个投币口,在设计接口和类之前,我们来看一下状态模式的UML图: State接口定义了一个所有具体状态的共同接口;任何状态都实...

weixin_34380781的博客 303

C#设计模式读书笔记之状态模式(State Pattern)

状态模式(State pattern)【使用频率:★★★☆☆】 1.概述:允许一个对象在其内部状态改变时改变它的行为。 2.解决的问题:主要解决的是当控制一个对象状态转换的条件过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的逻辑判断简单化。 3.模式中的角色   3.1上下文环境(Context):在Context类中维护一个抽象状态类State的实例,这个...

qq826364410的专栏 529

Spring框架之状态模式 (State Pattern)

状态模式是一种行为型设计模式,它将对象的状态封装为不同的状态类,并允许对象根据状态的变化而改变其行为。通过状态模式,可以避免复杂的条件判断语句,提高代码的可扩展性和维护性。在需要根据不同状态处理不同行为的场景下,状态模式是一个非常有用的设计模式。

欢迎来到我的博客!这里是一个专注于计算机技术的分享平台,涵盖编程开发、算法研究、系统架构、软件工程等多个领域。无论你是初学者还是资深开发者,都能在这里找到有价值的内容。 1262

The State Pattern 状态模式

A little known fact: the Strategy and State Patterns were twins separated at birth. As you know, the Strategy Pattern went on to create a wildly successful business around interchangeable algorithms

Peep Hole 1417

状态模式(State Pattern)

设计模式 - 吕震宇 .NET设计模式系列文章 薛敬明的专栏 乐在其中设计模式(C#) 设计模式24:State Pattern (状态模式) 英文原文:http://www.dofactory.com/Patterns/PatternState.aspx 一、State Pattern (状态模式) Define: Allow an object to alter

jiangxinyu的专栏 2313

状态模式【State Pattern】

现在城市发展很快,百万级人口的城市一堆一堆的,那其中有两个东西的发明在城市的发展中起到非常重要的作用:一个是汽车,一个呢是...,猜猜看,是什么?是电梯!汽车让城市可以横向扩展,电梯让城市可以纵向延伸,向空中伸展。汽车对城市的发展我们就不说了,电梯,你想想看,如果没有电梯,每天你需要爬 10 层楼梯,你是不是会崩溃掉?建筑师设计了一个没有电梯的建筑,那投资家肯定不愿意投资,那也是建筑师的耻辱呀,今

admin1973的专栏 1997
上一篇: 解释器模式
下一篇: 策略模式(Strategy Pattern)
code_Floyed
博客等级 码龄7年 3粉丝 56原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值