【设计模式】Java设计模式 - 状态模式

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

Java设计模式 - 状态模式

😄 不断学习才是王道
🔥 继续踏上学习之路,学之分享笔记
👊 总有一天我也能像各位大佬一样
🏆 一个有梦有戏的人 @怒放吧德德
🌝分享学习心得,欢迎指正,大家一起学习成长!

java设计模式2.jpg

简介

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

状态模式原理解析

在不同的状态会有自己不同的操作方法(行为),状态和行为是一一对应的,并且状态之间可以互相切换。
UML图:
状态模式.jpg

角色与职责

  • Context:环境角色,聚合State实例,用来定义当前状态。
  • State:抽象类-状态类,定义一些行为。
  • ConcreteState:具体的状态类,实现实现具体的行为。

状态模式实例

本次实验采用抽奖的案例来解析状态模式。

抽奖的流程是先扣除积分,抽奖,如果中奖则发放奖品。使用状态模式,需要定义不可抽奖、可以抽奖、发放奖品、奖品发送完成状态。在每个状态中都有各自的详细行为。

类图如图:
image.png

①、定义抽象状态类

里面包含扣除积分、是否中奖以及发放奖品,分别由各自状态去实现对应的方法。

package com.lyd.demo.state;
/**
 * @Author: lyd
 * @Description: 状态抽象类
 * @Date: 2022-09-12
 */
public abstract class State {
    // 扣除积分
    public abstract void deductMoney();
    // 是否抽中奖品
    public abstract boolean raffle();
    // 发放奖品
    public abstract  void dispensePrize();
}

②、定义具体状态

不可抽奖状态
初始状态,实现扣除积分,这个状态会扣除积分,这个状态还不能抽奖,调用抽奖和发放奖品都会提示不可以抽奖。

package com.lyd.demo.state;
import com.lyd.demo.activity.RaffleActivity;
/**
 * @Author: lyd
 * @Description: 子类 - 禁止抽奖
 * @Date: 2022-09-12
 */
public class NoRaffleState extends State{
    RaffleActivity activity;
    public NoRaffleState(RaffleActivity activity) {
        this.activity = activity;
    }
    /**
     * 扣除积分
     */
    @Override
    public void deductMoney() {
        // 抽奖的时候需要扣除积分
        System.out.println("扣除20积分,可以抽奖......");
        // 转换成可以抽奖的状态
        activity.setState(activity.getCanRaffleState());
    }
    /**
     * 是否可以抽奖
     * @return
     */
    @Override
    public boolean raffle() {
        System.out.println("当前状态不能抽奖......");
        return false;
    }
    /**
     * 发放奖品 - 当前状态不能发放
     */
    @Override
    public void dispensePrize() {
        System.out.println("当前状态不能发放奖品......");
    }
}

可以抽奖状态
具体实现抽奖行为,并且禁止扣除积分,和发放奖品,在抽奖获奖的时候会去将状态转换成发放奖品状态,反之则转换成不可以抽奖状态。

package com.lyd.demo.state;
import com.lyd.demo.activity.RaffleActivity;
import java.util.Random;
/**
 * @Author: lyd
 * @Description: 可以抽奖状态
 * @Date: 2022-09-12
 */
public class CanRaffleState extends State {
    RaffleActivity activity;
    public CanRaffleState(RaffleActivity activity) {
        this.activity = activity;
    }
    /**
     * 已经扣除积分了
     */
    @Override
    public void deductMoney() {
        System.out.println("不能重复扣除积分......");
    }
    @Override
    public boolean raffle() {
        System.out.println("正在抽奖,请稍等......");
        Random r = new Random();
        int num = r.nextInt(10);
        // 10%中奖机会
        if(num == 0){
            // 改变活动状态为发放奖品 context
            activity.setState(activity.getDispenseState());
            return true;
        }else{
            System.out.println("很遗憾没有抽中奖品!");
            // 改变状态为不能抽奖
            activity.setState(activity.getNoRaffleState());
            return false;
        }
    }
    @Override
    public void dispensePrize() {
        System.out.println("没中奖,不能发放奖品......");
    }
}

发放奖品状态
如果抽奖获奖了,就转换成该状态,在此状态依然是不允许扣除积分,以及抽奖也是不允许的,只能够实现发放奖品。发放奖品还要将状态转成不可抽奖状态,如果是奖品发放完了就切换成奖品发放完的状态。

package com.lyd.demo.state;
import com.lyd.demo.activity.RaffleActivity;
/**
 * @Author: lyd
 * @Description: 发放奖品状态
 * @Date: 2022-09-12
 */
public class DispenseState extends State {
    RaffleActivity activity;
    public DispenseState(RaffleActivity 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());
            System.out.println("抽奖活动结束!!!");
            System.exit(0);
        }
    }
}

奖品发放完状态

package com.lyd.demo.state;
import com.lyd.demo.activity.RaffleActivity;
/**
 * @Author: lyd
 * @Description: 奖品发放完的状态
 * @Date: 2022-09-12
 */
public class DispenseOutState extends State {
    RaffleActivity activity;
    public DispenseOutState(RaffleActivity 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("奖品发送完了,请下次再参加");
    }
}

③、定义活动类

对像的实例化,刚开始的状态是不可以抽奖的状态。

package com.lyd.demo.activity;
import com.lyd.demo.state.*;
/**
 * @Author: lyd
 * @Description: 活动
 * @Date: 2022-09-12
 */
public class RaffleActivity {
    // 状态变化
    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 RaffleActivity(int count) {
        this.state = getNoRaffleState();
        this.count = count;
    }
    //扣分, 调用当前状态的 deductMoney
    public void deductMoney() {
        this.state.deductMoney();
    }
    //抽奖
    public void raffle(){
        // 如果当前的状态是抽奖成功
        if(state.raffle()){
            //领取奖品
            state.dispensePrize();
        }

    }
    public State getState() {
        return state;
    }
    public void setState(State state) {
        this.state = state;
    }
    // 每领取一次奖品,count--
    public int getCount() {
        int curCount = count;
        count--;
        return curCount;
    }
    public void setCount(int count) {
        this.count = count;
    }
    public State getNoRaffleState() {
        return noRaffleState;
    }
    public void setNoRaffleState(State noRaffleState) {
        this.noRaffleState = noRaffleState;
    }
    public State getCanRaffleState() {
        return canRaffleState;
    }
    public void setCanRaffleState(State canRaffleState) {
        this.canRaffleState = canRaffleState;
    }
    public State getDispenseState() {
        return dispenseState;
    }
    public void setDispenseState(State dispenseState) {
        this.dispenseState = dispenseState;
    }
    public State getDispenseOutState() {
        return dispenseOutState;
    }
    public void setDispenseOutState(State dispenseOutState) {
        this.dispenseOutState = dispenseOutState;
    }
}

④、测试

实例化活动,通过调用扣分和抽奖方法。

package com.lyd.demo.test;

import com.lyd.demo.activity.RaffleActivity;

/**
 * @Author: lyd
 * @Description: 测试
 * @Date: 2022-09-12
 */
public class StateTest {
    public static void main(String[] args) {
        // 创建活动,输入奖品个数
        RaffleActivity activity = new RaffleActivity(2);
        for (int i = 0; i < 5; i++) {
            System.out.println("--------第" + (i + 1) + "次抽奖----------");
            // 参加抽奖,第一步点击扣除积分
            activity.deductMoney();
            // 第二步抽奖
            activity.raffle();
        }
    }
}

运行结果
image.png

👍创作不易,可能有些语言不是很通畅,如有错误请指正,感谢观看!记得一键三连哦!👍

💓德德小建议:

理解设计模式不是一件简单的事情,需要不断的学习和动手去练习,才能理解。只有掌握好设计模式,才能够真正的理解SpringAOP和Mybatis的底层原理。各位读者可以和我一样,动手敲一敲代码,甚至用不同的例子来做,通过debug一步一步调试,还有就是多看看别人的例子。能够有助于理解!谢谢各位观看指点!❤️ ❤️ ❤️
相关文章
|
13天前
|
设计模式 监控 算法
Java设计模式梳理:行为型模式(策略,观察者等)
本文详细介绍了Java设计模式中的行为型模式,包括策略模式、观察者模式、责任链模式、模板方法模式和状态模式。通过具体示例代码,深入浅出地讲解了每种模式的应用场景与实现方式。例如,策略模式通过定义一系列算法让客户端在运行时选择所需算法;观察者模式则让多个观察者对象同时监听某一个主题对象,实现松耦合的消息传递机制。此外,还探讨了这些模式与实际开发中的联系,帮助读者更好地理解和应用设计模式,提升代码质量。
Java设计模式梳理:行为型模式(策略,观察者等)
|
1月前
|
存储 设计模式 安全
Java设计模式-备忘录模式(23)
Java设计模式-备忘录模式(23)
|
1月前
|
设计模式 存储 缓存
Java设计模式 - 解释器模式(24)
Java设计模式 - 解释器模式(24)
|
13天前
|
设计模式 Java
Java设计模式
Java设计模式
22 0
|
16天前
|
设计模式 Java
Java设计模式之外观模式
这篇文章详细解释了Java设计模式之外观模式的原理及其应用场景,并通过具体代码示例展示了如何通过外观模式简化子系统的使用。
25 0
|
16天前
|
设计模式 Java
Java设计模式之桥接模式
这篇文章介绍了Java设计模式中的桥接模式,包括桥接模式的目的、实现方式,并通过具体代码示例展示了如何分离抽象与实现,使得两者可以独立变化。
32 0
|
16天前
|
设计模式 Java
Java设计模式之适配器模式
这篇文章详细讲解了Java设计模式中的适配器模式,包括其应用场景、实现方式及代码示例。
32 0
|
28天前
|
设计模式 数据库连接 PHP
PHP中的设计模式:提升代码的可维护性与扩展性在软件开发过程中,设计模式是开发者们经常用到的工具之一。它们提供了经过验证的解决方案,可以帮助我们解决常见的软件设计问题。本文将介绍PHP中常用的设计模式,以及如何利用这些模式来提高代码的可维护性和扩展性。我们将从基础的设计模式入手,逐步深入到更复杂的应用场景。通过实际案例分析,读者可以更好地理解如何在PHP开发中应用这些设计模式,从而写出更加高效、灵活和易于维护的代码。
本文探讨了PHP中常用的设计模式及其在实际项目中的应用。内容涵盖设计模式的基本概念、分类和具体使用场景,重点介绍了单例模式、工厂模式和观察者模式等常见模式。通过具体的代码示例,展示了如何在PHP项目中有效利用设计模式来提升代码的可维护性和扩展性。文章还讨论了设计模式的选择原则和注意事项,帮助开发者在不同情境下做出最佳决策。
|
8天前
|
设计模式 Java Kotlin
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
本教程详细讲解Kotlin语法,适合希望深入了解Kotlin的开发者。对于快速学习Kotlin语法,推荐查看“简洁”系列教程。本文重点介绍了构建者模式在Kotlin中的应用与改良,包括如何使用具名可选参数简化复杂对象的创建过程,以及如何在初始化代码块中对参数进行约束和校验。
12 3
|
1月前
|
设计模式 算法 安全
设计模式——模板模式
模板方法模式、钩子方法、Spring源码AbstractApplicationContext类用到的模板方法
设计模式——模板模式