【设计模式】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一步一步调试,还有就是多看看别人的例子。能够有助于理解!谢谢各位观看指点!❤️ ❤️ ❤️
相关文章
|
2天前
|
设计模式 算法 Java
[设计模式Java实现附plantuml源码~行为型]定义算法的框架——模板方法模式
[设计模式Java实现附plantuml源码~行为型]定义算法的框架——模板方法模式
|
2天前
|
设计模式 JavaScript Java
[设计模式Java实现附plantuml源码~行为型] 对象状态及其转换——状态模式
[设计模式Java实现附plantuml源码~行为型] 对象状态及其转换——状态模式
|
2天前
|
设计模式 存储 JavaScript
[设计模式Java实现附plantuml源码~创建型] 多态工厂的实现——工厂方法模式
[设计模式Java实现附plantuml源码~创建型] 多态工厂的实现——工厂方法模式
|
2天前
|
设计模式 Java Go
[设计模式Java实现附plantuml源码~创建型] 集中式工厂的实现~简单工厂模式
[设计模式Java实现附plantuml源码~创建型] 集中式工厂的实现~简单工厂模式
|
2天前
|
设计模式 存储 前端开发
Java从入门到精通:2.2.1学习Java Web开发,了解Servlet和JSP技术,掌握MVC设计模式
Java从入门到精通:2.2.1学习Java Web开发,了解Servlet和JSP技术,掌握MVC设计模式
|
8天前
|
设计模式 算法 Java
Java中的设计模式及其应用
【4月更文挑战第18天】本文介绍了Java设计模式的重要性及分类,包括创建型、结构型和行为型模式。创建型模式如单例、工厂方法用于对象创建;结构型模式如适配器、组合关注对象组合;行为型模式如策略、观察者关注对象交互。文中还举例说明了单例模式在配置管理器中的应用,工厂方法在图形编辑器中的使用,以及策略模式在电商折扣计算中的实践。设计模式能提升代码可读性、可维护性和可扩展性,是Java开发者的必备知识。
|
18天前
|
设计模式 SQL 算法
设计模式了解哪些,模版模式
设计模式了解哪些,模版模式
19 0
|
1月前
|
设计模式 Java uml
C++设计模式之 依赖注入模式探索
C++设计模式之 依赖注入模式探索
37 0
|
3月前
|
设计模式 存储 算法
Java 设计模式最佳实践:三、行为模式
Java 设计模式最佳实践:三、行为模式
22 0
|
2月前
|
设计模式 前端开发 JavaScript
观察者模式 vs 发布-订阅模式:两种设计模式的对决!
欢迎来到前端入门之旅!这个专栏是为那些对Web开发感兴趣、刚刚开始学习前端的读者们打造的。无论你是初学者还是有一些基础的开发者,我们都会在这里为你提供一个系统而又亲切的学习平台。我们以问答形式更新,为大家呈现精选的前端知识点和最佳实践。通过深入浅出的解释概念,并提供实际案例和练习,让你逐步建立起一个扎实的基础。无论是HTML、CSS、JavaScript还是最新的前端框架和工具,我们都将为你提供丰富的内容和实用技巧,帮助你更好地理解并运用前端开发中的各种技术。