设计模式の状态策略责任链模式

news2025/1/5 19:26:47

文章目录

  • 前言
  • 一、状态模式
  • 二、策略模式
  • 三、责任链模式


前言

  本篇是关于设计模式中的状态模式、策略模式、以及责任链模式的学习笔记。


一、状态模式

  状态模式是一种行为设计模式,核心思想在于,使某个对象在其内部状态改变时,改变该对象的行为,使对象看起来像是改变了其类。将状态的相关行为封装到独立的状态类中,并通过在运行时切换状态对象来改变对象的行为。实现方式在于,将状态抽取成单独的类,并由上下文类统一管理。
  状态模式的结构包括以下几个主要角色:

  1. 上下文类:它维护一个当前状态的实例,并且对客户端公开其接口。
  2. 抽象状态类:定义了所有具体状态类需要实现的接口,抽取出所有状态下共有的方法。
  3. 具体状态类:实现了抽象状态类,根据自身状态的特点,有选择性第重写父类方法的逻辑。

  假设需要设计一个抽奖系统,有四种状态:

  • 不能抽奖的状态
  • 可以抽奖的状态
  • 发放奖品的状态
  • 奖品发放完成的状态

  状态流转方式如下:
在这里插入图片描述  体现在代码上,首先设计一个抽象状态接口,该接口将各种状态下可能的操作进行聚合:

/**
 * 状态接口
 * 将各种状态下可能的操作聚合成一个接口
 * 实现类根据各自状态可能的业务去重写其中的方法
 */
public interface State {

    /**
     * 扣除积分
     */
    void deduceMoney();

    /**
     * 抽奖
     * @return
     */
    boolean raffle();

    /**
     * 发放奖品
     */
    void dispensePrice();
}

  抽象接口具体的实现
  不能抽奖状态,在此状态下只能去做出扣减积分的操作,扣减完成积分后,状态会变更为可抽奖状态

/**
 * 不能抽奖的状态
 */
public class NoRaffleState implements State{

    RaffleActivity raffleActivity;

    public NoRaffleState(RaffleActivity raffleActivity) {
        this.raffleActivity = raffleActivity;
    }

    /**
     * 扣除积分
     */
    @Override
    public void deduceMoney() {
        System.out.println("扣除50积分,可以抽奖");
        raffleActivity.setState(raffleActivity.getCanRaffleState());
    }

    /**
     * 抽奖
     *
     * @return
     */
    @Override
    public boolean raffle() {
        System.out.println("扣除积分方能抽奖");
        return false;
    }

    /**
     * 发放奖品
     */
    @Override
    public void dispensePrice() {
        System.out.println("不能发放奖品");
    }
}

  可抽奖状态,只能进行抽奖操作:

  • 未抽中奖品,重新回到不可抽奖状态
  • 抽中了奖品,流转到发送奖品状态
/**
 * 可以抽奖的状态
 */
public class CanRaffleState implements State{

    RaffleActivity raffleActivity;

    public CanRaffleState(RaffleActivity raffleActivity) {
        this.raffleActivity = raffleActivity;
    }


    /**
     * 扣除积分
     */
    @Override
    public void deduceMoney() {
        System.out.println("已经扣除积分,可以抽奖");
    }

    /**
     * 抽奖
     *
     * @return
     */
    @Override
    public boolean raffle() {
        System.out.println("正在抽奖,请稍等");
        int num = new Random().nextInt(10);
        if (num == 0){
            //中奖了,发放奖品
            raffleActivity.setState(raffleActivity.getDispenseState());
            return true;
        }else {
            System.out.println("很遗憾,您没有中奖");
            //回到不能抽奖的状态
            raffleActivity.setState(raffleActivity.getNoRaffleState());
            return false;
        }
    }

    /**
     * 发放奖品
     */
    @Override
    public void dispensePrice() {
        System.out.println("没中奖,不能发放奖品");
    }
}

  发放奖品状态,只能进行发放奖品的操作:

  • 奖品数量充足,流转到奖品发送完成状态。
  • 奖品数量不足,改变状态为不能抽奖
/**
 * 发放奖品的状态
 */
public class DispenseState implements State{

    RaffleActivity raffleActivity;

    public DispenseState(RaffleActivity raffleActivity) {
        this.raffleActivity = raffleActivity;
    }

    /**
     * 扣除积分
     */
    @Override
    public void deduceMoney() {
        System.out.println("不能扣除积分");
    }

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

    /**
     * 发放奖品
     */
    @Override
    public void dispensePrice() {
        if (raffleActivity.getCount()>0){
            System.out.println("恭喜中奖了");
            //改变状态为不能抽奖
            raffleActivity.setState(raffleActivity.getNoRaffleState());
        }else {
            System.out.println("很遗憾,奖品发送完了");
            //改变状态为奖品发送完成
            raffleActivity.setState(raffleActivity.getDispenseOutState());
        }

    }
}

  奖品发放完成,则不可以进行任何操作

/**
 * 奖品发放完成的状态
 */
public class DispenseOutState implements State{

    RaffleActivity raffleActivity;

    public DispenseOutState(RaffleActivity raffleActivity) {
        this.raffleActivity = raffleActivity;
    }

    /**
     * 扣除积分
     */
    @Override
    public void deduceMoney() {
        System.out.println("奖品发送完了,请下次再参加");
    }

    /**
     * 抽奖
     *
     * @return
     */
    @Override
    public boolean raffle() {
        System.out.println("奖品发送完了,请下次再参加");
        return false;
    }

    /**
     * 发放奖品
     */
    @Override
    public void dispensePrice() {
        System.out.println("奖品发送完了,请下次再参加");
    }
}

  创建一个上下文类,对状态进行统一管理,同时对状态进行初始化,并且上面的具体状态类,也聚合了上下文类的对象:

/**
 * 抽奖的行为
 */
public class RaffleActivity {

    /**
     * 初始的状态
     */
    State state = null;

    /**
     * 初始的数量
     */
    int count = 0;

    State canRaffleState = new CanRaffleState(this);
    State noRaffleState = new NoRaffleState(this);
    State dispenseOutState = new DispenseOutState(this);
    State dispenseState = new DispenseState(this);

    public RaffleActivity(int count) {
        //初始状态,不能抽奖
        this.state = getNoRaffleState();
        this.count = count;
    }

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

    /**
     * 抽奖
     */
    public void raffle(){
        if (state.raffle()){
            //领取奖品
            state.dispensePrice();
        }
    }


    public State getState() {
        return state;
    }

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

    public int getCount() {
        int curCount = this.count;
        count--;
        return curCount;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public State getCanRaffleState() {
        return canRaffleState;
    }

    public void setCanRaffleState(State canRaffleState) {
        this.canRaffleState = canRaffleState;
    }

    public State getNoRaffleState() {
        return noRaffleState;
    }

    public void setNoRaffleState(State noRaffleState) {
        this.noRaffleState = noRaffleState;
    }

    public State getDispenseOutState() {
        return dispenseOutState;
    }

    public void setDispenseOutState(State dispenseOutState) {
        this.dispenseOutState = dispenseOutState;
    }

    public State getDispenseState() {
        return dispenseState;
    }

    public void setDispenseState(State dispenseState) {
        this.dispenseState = dispenseState;
    }
}
public class Client {
    public static void main(String[] args) {
        RaffleActivity raffleActivity = new RaffleActivity(1);

        for (int i = 0; i < 3; i++) {
            //扣积分
            raffleActivity.deduceMoney();
            //抽奖
            raffleActivity.raffle();
        }
    }
}

小结
状态模式的优缺点
优点:

  • 遵循单一职责原则:将与状态相关的代码封装到独立类中。
  • 开闭原则:添加新状态非常方便,无需修改现有代码。
  • 消除大量条件语句:状态切换通过对象替换实现,而非复杂的条件判断。

缺点:

  • 类的数量增加:每个状态都需要创建一个类,可能导致类数量增多。
  • 状态之间的耦合:状态类之间可能需要频繁切换,会导致一定程度的耦合。

二、策略模式

  策略模式是一种行为设计模式,核心思想在于,定义了一组算法,将每个算法封装到独立的类中,使它们可以相互替换。
  策略模式通常包括以下角色:

  1. 上下文类:持有一个策略对象的引用,并且初始化具体策略。
  2. 抽象策略类:定义了所有具体策略类需要实现的接口。
  3. 具体策略类:实现抽象策略类,包含具体的算法或行为。

  假设目前有一个方法,需要根据参数中传入的不同的业务类型,执行不同业务的分派,如果使用传统方式,则会利用switch或者if-else实现,将来需要扩展的时候,需要对分支代码进行修改:

/**
 * 业务处理接口
 */
public interface BusinessClass {

    /**
     * 处理业务
     */
    void handleBusiness(int type);
}
public class BusinessClassImpl implements BusinessClass{


    /**
     * 处理业务
     * 根据传入的参数进行分发
     */
    @Override
    public void handleBusiness(int type) {

        switch (type){
            case 1:
                this.handleBusiness1();
                break;
            case 2:
                this.handleBusiness2();
                break;
            case 3:
                this.handleBusiness3();
                break;
            default:
                break;
        }
    }

    private void handleBusiness3() {
        System.out.println("业务3的具体逻辑");
    }

    private void handleBusiness2() {
        System.out.println("业务2的具体逻辑");
    }

    private void handleBusiness1() {
        System.out.println("业务1的具体逻辑");
    }
}

  使用策略模式改造,则可以抽取一个策略接口

/**
 * 业务策略接口
 */
public interface BusinessStrategy {

    /**
     * 处理具体的业务逻辑
     */
    void handleBusiness();
}

  将传统方式中,每个分支中的方法都抽取到一个单独的类中,实现策略接口

public class Business1 implements BusinessStrategy{
    /**
     * 处理具体的业务逻辑
     */
    @Override
    public void handleBusiness() {
        System.out.println("处理业务逻辑1");
    }
}
public class Business2 implements BusinessStrategy{
    /**
     * 处理具体的业务逻辑
     */
    @Override
    public void handleBusiness() {
        System.out.println("处理业务逻辑2");
    }
}
public class Business3 implements BusinessStrategy{
    /**
     * 处理具体的业务逻辑
     */
    @Override
    public void handleBusiness() {
        System.out.println("处理业务逻辑3");
    }
}

  在上下文类中,对其进行统一的管理,业务代码只需要注入上下文类,调用其中的方法即可。

public class Context {

    private Map<Integer, BusinessStrategy> strategyMap = new HashMap<>();

    /**
     * 初始化上下文,k业务类型 v 业务类型具体的逻辑
     */
    public Context(){
        strategyMap.put(1, new Business1());
        strategyMap.put(2, new Business2());
        strategyMap.put(3, new Business3());
    }

    /**
     * 处理业务
     * 根据传入的参数进行分发
     */
    public void handleBusiness(int type) {
        BusinessStrategy strategy = strategyMap.get(type);
        if (strategy != null) {
            strategy.handleBusiness();
        } else {
            System.out.println("无效的业务类型");
        }
    }
}

小结
策略模式的优缺点
优点:

  • 遵循开闭原则:添加新策略无需修改现有代码,只需扩展新策略类。
  • 消除条件语句:避免了复杂的 if-else 或 switch-case 语句。
  • 提高灵活性:客户端可以动态选择策略。

缺点:

  • 类数量增加:每种策略需要创建一个类,可能导致类的数量过多。
  • 客户端需要了解不同策略:客户端必须知道有哪些策略才能选择合适的策略。

三、责任链模式

  责任链模式是一种行为设计模式,核心目的在于,将请求的处理责任沿着一条链传递,直到有对象处理这个请求为止。责任链模式将请求的发送者和接收者解耦,且可以动态地调整链条上的处理顺序。
  责任链模式通常包含以下角色:

  1. 抽象处理者:定义了处理请求的接口,以及一个指向下一个处理者的引用。(即将自身作为属性存放在类中)
  2. 具体处理者:继承了抽象处理者,具体去实现各自处理请求的逻辑,以及无法处理时/处理完成时,应该调用的下一个处理者
  3. 客户端:创建并组装责任链,通常会将请求发送给责任链的首个处理者

  下面来看一个案例:假设某个学校,购买教材,器材,根据金额不同,需要审批的级别也不同。
  首先构建一个请求对象

public class Request {

    /**
     * 请求id
     */
    protected int id = 0;

    /**
     * 价格
     */
    protected int price = 0;

    public Request() {
    }

    public Request(int id, int price) {
        this.id = id;
        this.price = price;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }
}

  然后定义一个抽象处理者

/**
 * 抽象审批人
 */
public abstract class Approver {

    /**
     * 审批人名称
     */
    protected String name;

    /**
     * 持有自己的引用
     */
    protected Approver approver;

    public Approver() {
    }

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

    public void setApprover(Approver approver) {
        this.approver = approver;
    }

    /**
     * 子类具体去实现处理请求的逻辑
     * @param request
     */
    abstract void handleReq(Request request);

}

  定义具体处理人,继承抽象处理人,编写自己处理的判断逻辑:

public class TeachingDirector extends Approver{


    public TeachingDirector(String name){
        super(name);
    }

    /**
     * 子类具体去实现处理请求的逻辑
     *
     * @param request
     */
    @Override
    void handleReq(Request request) {
        if (request.getPrice()<= 5000){
            System.out.println("请求编号"+ request.id + "已经被" + name + "处理");
        }else {
            approver.handleReq(request);
        }
    }
}
public class Dean extends Approver{

    public Dean(String name){
        super(name);
    }

    /**
     * 子类具体去实现处理请求的逻辑
     *
     * @param request
     */
    @Override
    void handleReq(Request request) {
        if (request.getPrice()<= 10000){
            System.out.println("请求编号"+ request.id + "已经被" + name + "处理");
        }else {
            approver.handleReq(request);
        }
    }
}
public class Principal extends Approver{

    public Principal(String name){
        super(name);
    }

    /**
     * 子类具体去实现处理请求的逻辑
     *
     * @param request
     */
    @Override
    void handleReq(Request request) {
        if (request.getPrice()<= 20000){
            System.out.println("请求编号"+ request.id + "已经被" + name + "处理");
        }else {
            approver.handleReq(request);
        }
    }
}

  最后由客户端对其进行统一组装:

public class Client {
    public static void main(String[] args) {

        Request request = new Request(1, 8000);

        Dean dean = new Dean("院长");
        TeachingDirector teachingDirector = new TeachingDirector("教学主任");
        Principal principal = new Principal("校长");
        //设置下一个审批者
        teachingDirector.setApprover(dean);
        dean.setApprover(principal);
        principal.setApprover(teachingDirector);

        //8000 教学主任处理不了,交给下一级(院长)处理
        teachingDirector.handleReq(request);
    }
}

小结
责任链模式的优缺点

优点:

  • 降低耦合度:请求发送者与接收者解耦,无需关心由谁处理请求。
  • 动态灵活:可以在运行时动态调整责任链的结构。
  • 增强扩展性:新增处理者无需修改现有代码。

缺点:

  • 链条可能过长:请求可能需要经过多个处理者,性能可能受影响。
  • 调试困难:由于请求的处理流程不明确,可能导致调试复杂。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2270485.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【网络协议】路由信息协议 (RIP)

未经许可&#xff0c;不得转载。 路由信息协议&#xff08;Routing Information Protocol&#xff0c;简称 RIP&#xff09;是一种使用跳数&#xff08;hop count&#xff09;作为路由度量标准的路由协议&#xff0c;用于确定源网络和目标网络之间的最佳路径。 文章目录 什么是…

linux下安装达梦数据库v8详解

目录 操作系统、数据库 1、下载达梦数据库 2、安装前准备 2.1、建立数据库用户和组 2.2、修改文件打开最大数 2.3、挂载镜像 2.4、新建安装目录 3、数据库安装 4、配置环境变量 5、初始化数据库实例 6、注册服务 7、使用数据库 8、卸载数据库 9、多实例管理 10、…

小程序租赁系统的优势与应用探索

内容概要 小程序租赁系统&#xff0c;听起来很高大上&#xff0c;但实际上它比你想象的要实用得多&#xff01;设想一下&#xff0c;几乎所有的租赁需求都能通过手机轻松解决。这种系统的便捷性体现在让用户随时随地都能发起租赁请求&#xff0c;而不再受制于传统繁琐的手续。…

(leetcode算法题)​122. 买卖股票的最佳时机 II​ 和 123. 买卖股票的最佳时机 III

这两个题都可以进行转化&#xff0c;转换成等价问题求解 对于122的等价转换 求出所有能够赚钱的区间&#xff0c;这些区间满足一下特点 1. 首尾相接&#xff0c; 2. 区间末尾的值大于区间开头的值 3. 每个区间尽可能的小 新的问题只要用贪心的思想就能求得问题的解 只要求出上…

oceanbase集群访问异常问题处理

1.报错现象 2.问题排查 检查obproxy状态发现为不可用状态 重启obproxy 依次重启Obproxy集群 观察任务状态 重启完成 Obproxy状态正常 3.验证登录 登录成功

WeNet:面向生产的流式和非流式端到端语音识别工具包

这篇文章介绍了WeNet&#xff0c;一个面向生产的开源端到端&#xff08;E2E&#xff09;语音识别工具包。WeNet的主要特点和贡献如下&#xff1a; 统一流式和非流式识别&#xff1a;提出了一种名为U2的两阶段框架&#xff0c;能够在单一模型中同时支持流式和非流式语音识别&…

ArcGIS计算矢量要素集中每一个面的遥感影像平均值、最大值等统计指标

本文介绍在ArcMap软件中&#xff0c;基于矢量面要素集&#xff0c;计算在其中每一个面区域内&#xff0c;遥感影像的像元个数、平均值、总和等统计值&#xff0c;并将统计信息附加到矢量图层的属性表中的方法。 首先&#xff0c;明确一下本文的需求。现在有一个矢量面要素集&am…

Wallpaper壁纸制作学习记录13

骨骼物理模拟 Wallpaper Engine还允许您为人偶变形骨骼配置某些物理模拟。选择骨骼时&#xff0c;点击编辑约束来配置骨骼这些属性。 警告 请记住&#xff0c;物理模拟可能会根据用户的最大FPS设置略微改变其行为。 Wallpaper Engine编辑器将始终以高帧速率渲染。您可以将壁纸…

CertiK《Hack3d:2024年度安全报告》(附报告全文链接)

CertiK《Hack3d&#xff1a;2024年度安全报告》现已发布&#xff0c;本次报告深入分析了2024年Web3.0领域的安全状况。2024年损失总额超过23亿美元&#xff0c;同比增幅高达31.61%&#xff1b;其中&#xff0c;12月的损失金额最少。过去一年&#xff0c;网络钓鱼攻击和私钥泄露…

SpiderFlow平台v0.5.0之数据库连接

一、寻找lib目录安装方式 在 SpiderFlow 平台中&#xff0c;连接数据库时需要指定数据库的 DriverClassName&#xff0c;并确保正确配置数据库驱动。通常&#xff0c;驱动文件&#xff08;JAR 文件&#xff09;需要放置在指定的文件夹中&#xff0c;以便 SpiderFlow 可以找到并…

如何在notepad++里面,修改注释颜色

问题&#xff1a;我使用notepad加载.bib格式的文件&#xff0c;我想把第一行的GSA弄成紫色的&#xff0c;并且注释的格式是&#xff1a;%注释% 实现以后得效果展示&#xff1a; 接下来进行一步步讲解。 1. 不同的文件使用的语言不同&#xff0c;于是需要自己创建一个语言。如…

生态碳汇涡度相关监测与通量数据分析实践技术应用

1.以涡度通量塔的高频观测数据为例&#xff0c;基于MATLAB开展上机操作&#xff1a; 2.涡度通量观测基本概况&#xff1a;观测技术方法、数据获取与预处理等 3.涡度通量数据质量控制&#xff1a;通量数据异常值识别与剔除等 4.涡度通量数据缺失插补&#xff1a;结合气象数据…

[QT]控件的核心属性

一、控件的核心属性 1.enable属性 表示一个控件是否可用&#xff0c;可以用isEnabled()接口获取到当前控件的可用状态&#xff0c;同时来提供了setEnabled()接口设置控件是否可用&#xff0c;传递的参数为true和false。 isEnabled(); setEnabled(bool); Demo&#xff1a;通过一…

Vue 3 slot/插槽继承使用方法示例(基于 Ant Design Vue)

目录 Vue 3 插槽继承使用方法示例&#xff08;基于 Ant Design Vue&#xff09; 实例演示 背景 问题 解决方案&#xff1a;插槽继承 如何解决 插槽继承的原理 实现步骤 1. 子组件&#xff1a;封装 EaAutoComplete.vue 说明&#xff1a; 2. 父组件&#xff1a;自定义插…

成立一家无人机培训机构需要哪些基础配置

成立一家无人机培训机构&#xff0c;需要一系列基础配置来确保教学质量、学员安全以及机构的正常运营。以下是根据公开发布的信息整理出的关键基础配置&#xff1a; 一、场地配置 1. 飞行场&#xff1a;提供一个安全、宽敞的室外飞行环境&#xff0c;面积最好大于三千平米&…

【ACCSS】2024年亚信安全云认证专家题库

文件包含&#xff1a; 亚信安全ACCSS认证2019年真题&#xff08;1&#xff09; 亚信安全ACCSS认证2019年真题&#xff08;2&#xff09; 亚信安全ACCSS认证2019年真题&#xff08;3&#xff09; 亚信安全ACCSS认证2020年真题&#xff08;1&#xff09; 亚信安全ACCSS认证2020年…

探索 JMeter While Controller:循环测试的奇妙世界

嘿&#xff0c;宝子们&#xff01;今天咱们就来聊聊 JMeter 里超级厉害的 While 控制器&#xff0c;它就像是一把神奇的钥匙&#xff0c;能帮我们打开循环测试的大门&#xff0c;模拟出各种各样复杂又有趣的场景哦&#xff01; 一、While 控制器初印象 想象一下&#xff0c;你…

麒麟信安云在长沙某银行的应用入选“云建设与应用领航计划(2024)”,打造湖湘金融云化升级优质范本

12月26日&#xff0c;2024云计算产业和标准应用大会在北京成功召开。大会汇集政产学研用各方专家学者&#xff0c;共同探讨云计算产业发展方向和未来机遇&#xff0c;展示云计算标准化工作重要成果。 会上&#xff0c;云建设与应用领航计划&#xff08;2024&#xff09;建云用…

LeetCode算法题——螺旋矩阵ll

题目描述 给你一个正整数n&#xff0c;生成一个包含1到n2所有元素&#xff0c;且元素按顺时针顺序螺旋排列的n x n正方形矩阵matrix 。 示例 输入&#xff1a;n 3 输出&#xff1a;[[1,2,3],[8,9,4],[7,6,5]]题解 思路&#xff1a; 将整个过程分解为逐圈填充的过程&#xf…

设计模式 创建型 原型模式(Prototype Pattern)与 常见技术框架应用 解析

原型模式&#xff08;Prototype Pattern&#xff09;是一种创建型设计模式&#xff0c;其核心思想在于通过复制现有的对象&#xff08;原型&#xff09;来创建新的对象&#xff0c;而非通过传统的构造函数或类实例化方式。这种方式在需要快速创建大量相似对象时尤为高效&#x…