对策略模式的理解

目录

  • 一、场景
    • 1、题目描述 【[来源](https://kamacoder.com/problempage.php?pid=1082)】
    • 2、输入描述
    • 3、输出描述
    • 4、输入示例
    • 5、输出示例
  • 二、不使用策略模式
  • 三、使用策略模式
    • 1、不优雅的实现
    • 2、策略模式 + 简单工厂模式
      • 2.1 代码
      • 2.2 优点
      • 2.3 另一种实现方式
  • 四、个人思考

一、场景

  • 程序员除了会ctrl+ c + ctrl + v之外,最擅长的莫过于写if...else...了,哈哈:)
  • 有些场景下,我们可以预料到,会写非常多的if...else if...else if ... else if ...。这时候,可以使用策略模式。

1、题目描述 【来源】

小明家的超市推出了不同的购物优惠策略,你可以根据自己的需求选择不同的优惠方式。其中,有两种主要的优惠策略:

  1. 九折优惠策略:原价的90%。
  2. 满减优惠策略:购物满一定金额时,可以享受相应的减免优惠。

具体的满减规则如下:
满100元减5元
满150元减15元
满200元减25元
满300元减40元

请你设计一个购物优惠系统,用户输入商品的原价和选择的优惠策略编号,系统输出计算后的价格。

2、输入描述

输入的第一行是一个整数 N(1 ≤ N ≤ 20),表示需要计算优惠的次数。
接下来的 N 行,每行输入两个整数,第一个整数M( 0 < M < 400) 表示商品的价格, 第二个整数表示优惠策略,1表示九折优惠策略,2表示满减优惠策略

3、输出描述

每行输出一个数字,表示优惠后商品的价格

4、输入示例

4
100 1
200 2
300 1
300 2

5、输出示例

90
175
270
260

二、不使用策略模式

  • 代码:
public class Application {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();

        for (int i = 0; i < n; i++) {
            int price = scanner.nextInt();
            int strategyNum = scanner.nextInt();

            if (strategyNum == 1) {
                System.out.println((int) (price * 0.9));
            } else if (strategyNum == 2) {
                if (price < 100) {
                    System.out.println(price);
                } else if (price < 150) {
                    // 满100元减5元
                    System.out.println(price - 5);
                } else if (price < 200) {
                    // 满150元减15元
                    System.out.println(price - 15);
                } else if (price < 300) {
                    // 满200元减25元
                    System.out.println(price - 25);
                } else {
                    // 满300元减40元
                    System.out.println(price - 40);
                }

            } else {
                throw new RuntimeException("Invalid strategy number");
            }
        }

    }
}
  • 问题:
    • 可以预见的是,随着发展,优惠策略肯定不止一种。
    • 因此,可以用策略模式优化代码。

三、使用策略模式

1、不优雅的实现

  • 策略
public interface Strategy<T> {
    void execute(T data);
}

@AllArgsConstructor
public class DiscountStrategy implements Strategy<Integer> {
    private Double discount;

    @Override
    public void execute(Integer data) {
        System.out.println((int) (data * discount));
    }
}

public class FullMinusStrategy implements Strategy<Integer> {
    @Override
    public void execute(Integer price) {
        if (price < 100) {
            System.out.println(price);
        } else if (price < 150) {
            // 满100元减5元
            System.out.println(price - 5);
        } else if (price < 200) {
            // 满150元减15元
            System.out.println(price - 15);
        } else if (price < 300) {
            // 满200元减25元
            System.out.println(price - 25);
        } else {
            // 满300元减40元
            System.out.println(price - 40);
        }
    }
}
  • 客户端
public class Application {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();

        Strategy strategy = null;
        for (int i = 0; i < n; i++) {
            int price = scanner.nextInt();
            int strategyNum = scanner.nextInt();

            switch (strategyNum) {
                case 1:
                    strategy = new DiscountStrategy(0.9D);
                    break;
                case 2:
                    strategy = new FullMinusStrategy();
                    break;
                default:
                    new RuntimeException("Strategy not found");
            }

            strategy.execute(price);
        }
    }
}
  • 啊这,这不还是写if...esle吗?(switch只是对if...else的美化而已)
  • 我们其实已经知道<1, DiscountStrategy>, <2, FullMinusStrategy>,因此,可以提前建立联系。

2、策略模式 + 简单工厂模式

2.1 代码

  • 策略和上面一样
public interface Strategy<T> {
    ...
}

@AllArgsConstructor
public class DiscountStrategy implements Strategy<Integer> {
    ...
}

public class FullMinusStrategy implements Strategy<Integer> {
    ...
}
  • 对策略的封装:
public class StrategyManager {
    private static final Map<Integer, Strategy> strategies = new HashMap<>();

    public StrategyManager() {
        strategies.put(1, new DiscountStrategy(0.9D));
        strategies.put(2, new FullMinusStrategy());
    }

    public void execute(Integer strategyNum, Integer data) {
        Strategy strategy = strategies.get(strategyNum);
        if (strategy == null) {
            throw new RuntimeException("Strategy not found");
        }

        strategy.execute(data);
    }
}
  • 客户端:
public class Application {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();

        StrategyManager strategyManager = new StrategyManager();
        for (int i = 0; i < n; i++) {
            int price = scanner.nextInt();
            int strategyNum = scanner.nextInt();

            strategyManager.execute(strategyNum, price);
        }
    }
}

2.2 优点

  • 即使再增加一种策略,也不用修改客户端的代码。
  • 然而,没有Spring的辅助下,需要自己构建Map<Integer, Strategy> strategies,这使得增加一种策略时,还得修改StrategyManager类。

2.3 另一种实现方式

  • 策略:
public interface Strategy<T, R> {
    boolean match(R matchContext);
    void execute(T data);
}

@AllArgsConstructor
public class DiscountStrategy implements Strategy<Integer, Integer> {
    private Double discount;

    @Override
    public boolean match(Integer matchContext) {
        return matchContext == 1;
    }

    @Override
    public void execute(Integer data) {
        System.out.println((int) (data * discount));
    }
}

public class FullMinusStrategy implements Strategy<Integer, Integer> {
    @Override
    public boolean match(Integer matchContext) {
        return matchContext == 2;
    }

    @Override
    public void execute(Integer price) {
        if (price < 100) {
            System.out.println(price);
        } else if (price < 150) {
            // 满100元减5元
            System.out.println(price - 5);
        } else if (price < 200) {
            // 满150元减15元
            System.out.println(price - 15);
        } else if (price < 300) {
            // 满200元减25元
            System.out.println(price - 25);
        } else {
            // 满300元减40元
            System.out.println(price - 40);
        }
    }
}
  • 对策略的封装:
public class StrategyManager {
//    private static final Map<Integer, Strategy> strategies = new HashMap<>();
    private static final List<Strategy> strategies = new ArrayList<>();

    public StrategyManager() {
        strategies.add(new DiscountStrategy(0.9D));
        strategies.add(new FullMinusStrategy());
    }

    public void execute(Integer strategyNum, Integer data) {
        Strategy strategy = strategies.stream()
                .filter(s -> s.match(strategyNum))
                .findFirst()
                .orElse(null);
        if (strategy == null) {
            throw new RuntimeException("Strategy not found");
        }

        strategy.execute(data);
    }
}
  • 客户端和上面一样。

个人觉得这种方式更灵活。

四、个人思考

  • 当遇到写非常多的if...else if...else if ... else if ...时,说明<规则,处理>是确定的。
  • 那么完全可以抽象为:
public interface Strategy<T, R> {
    boolean match(R matchContext); // 匹配规则
    void execute(T data); // 处理数据
}

各种具体的xxxStrategy
@Component
public class StrategyManager {
    @Autowired
    private List<Strategy> strategies;

    public void execute(Integer strategyNum, Integer data) {
        Strategy strategy = strategies.stream()
                .filter(s -> s.match(strategyNum))
                .findFirst()
                .orElse(null);
        if (strategy == null) {
            throw new RuntimeException("Strategy not found");
        }

        strategy.execute(data);
    }
}
  • 小插曲,后续会写文章解释。
@Component
public class StrategyManager {
	// 字段注入,不支持静态变量。
    @Autowired
    private static List<Strategy> strategies;
	...
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

android布局

LinerLayout 权重分配的是剩余空间 RelativeLayout

Python脚本实现PC端大麦网自动购票(Selenium自动化测试工具)

文章目录 Selenium 简介Selenium webdriver 文档chromedriver&#xff08;谷歌浏览器驱动&#xff09;chromedriver 下载配置环境变量 大麦网购票脚本网页 dom 元素 启用远程调试&#xff08;操作已打开的窗口&#xff09; Selenium 简介 Selenium 是一个用于自动化测试的工具…

目标检测与追踪AI算法模型及边缘计算智能分析网关V4的算法应用

目标检测与追踪是计算机视觉领域中的一个重要任务&#xff0c;主要用于识别图像或视频中的目标&#xff0c;并跟踪它们的运动轨迹。针对这一任务&#xff0c;有许多先进的AI算法模型&#xff0c;例如&#xff1a; YOLO&#xff08;You Only Look Once&#xff09;&#xff1a;…

linux 设备树-of_address_to_resource

实例分析-reg 属性解析(基于ranges属性) /{#address-cells <0x01>;#size-cells <0x01>;soc {compatible "simple-bus";#address-cells <0x01>;#size-cells <0x01>;ranges <0x7e000000 0x3f000000 0x1000000 0x40000000 0x40000000…

怎么把图片转换为二维码?3个步骤轻松制作图片二维码

图片的二维码是怎么做成的呢&#xff1f;现在很多场景下的二维码&#xff0c;用手机扫码可以展现出对应的图片信息。通过这种方式来传递图片对于用户体验与很好的效果&#xff0c;而且也方便制作者通过这种方式来快速完成图片信息的传递&#xff0c;与传统方式相比成本更低&…

客服专用的宝藏快捷回复软件

提起客服&#xff0c;很多人会觉得现在智能机器人的自动回复功能就可以将其替代。我始终不是这么认为的。人工客服始终能为一家店铺乃至一个企业起着非常关键重要的作用。今天就来给大家推荐一个客服专用的宝藏软件——客服宝聊天助手。感兴趣的话&#xff0c;可以发给你的客服…

面向对象开发技术(第三周)

回顾 上一堂课主要学习了面向对象编程与非面向对象编程&#xff08;面向功能、过程编程&#xff09;&#xff0c;本节课就重点来看看面向对象编程中的一个具体思想——抽象 面向对象编程的特性&#xff1a;1、封装性 2、继承性 3、多态性 封装&#xff1a;意味着提供服务接口…

异常风云:解码 Java 异常机制

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一个人虽可以走的更快&#xff0c;但一群人可以走的更远。 我是一名后…

【论文阅读】《Octopus v2: On-device language model for super agent》,端侧大模型的应用案例

今年LLM的发展趋势之一&#xff0c;就是端侧LLM快速发展&#xff0c;超级APP入口之争异常激烈。不过&#xff0c;端侧LLM如何应用&#xff0c;不知道细节就很难理解。正好&#xff0c;《Octopus v2: On-device language model for super agent》这篇文章可以解惑。 对比部署在…

JTAG访问xilinx FPGA的IDCODE

之前调试过xilinx的XVC&#xff08;Xilinx virtual cable&#xff09;&#xff0c;突然看到有人搞wifi-JTAG&#xff08;感兴趣可以参考https://github.com/kholia/xvc-esp8266&#xff09;&#xff0c;也挺有趣的。就突然想了解一下JTAG是如何运作的&#xff0c;例如器件识别&…

普通话水平测试用朗读作品60篇-(练习版)

普通话考试题型有读单音节字词、读多音节字词、朗读作品和命题说话。 具体分值如下&#xff1a; 1、读单音节字词100个&#xff0c;占10分&#xff1b;目的考查应试人普通话声母、韵母和声调的发音。 2、读双音节词语50个&#xff0c;占20分&#xff1b;目的是除了考查应试人声…

骨传导耳机怎么选?精心挑选热销排行前五的骨传导耳机推荐!

近几年&#xff0c;骨传导耳机作为新型蓝牙耳机款式&#xff0c;已经得到大家有效认可&#xff0c;可以说已经适用于日常中的各种场景中&#xff0c;比如运动场景&#xff0c;凭借舒适的佩戴体验和保护运动安全的特点深受到运动爱好者的欢迎&#xff0c;作为一个经验丰富的数码…

Linux网络—DNS域名解析服务

目录 一、BIND域名服务基础 1、DNS系统的作用及类型 DNS系统的作用 DNS系统类型 DNS域名解析工作原理&#xff1a; DNS域名解析查询方式&#xff1a; 2、BIND服务 二、使用BIND构建域名服务器 1、构建主、从域名服务器 1&#xff09;主服务器配置&#xff1a; 2&…

Windows主机入侵检测与防御内核技术深入解析

第2章 模块防御的设计思想 2.1 执行与模块执行 本章内容为介绍模块执行防御。在此我将先介绍“执行”分类&#xff0c;以及“模块执行”在“执行”中的位置和重要性。 2.1.1 初次执行 恶意代码&#xff08;或者行为&#xff09;要在被攻击的机器上执行起来&#xff0c;看起…

C语言----单链表的实现

前面向大家介绍了顺序表以及它的实现&#xff0c;今天我们再来向大家介绍链表中的单链表。 1.链表的概念和结构 1.1 链表的概念 链表是一种在物理结构上非连续&#xff0c;非顺序的一种存储结构。链表中的数据的逻辑结构是由链表中的指针链接起来的。 1.2 链表的结构 链表…

茴香豆:搭建你的RAG智能助理-笔记三

本次课程由书生浦语社区贡献者【北辰】老师讲解【茴香豆&#xff1a;搭建你的 RAG 智能助理】课程 课程视频&#xff1a;https://www.bilibili.com/video/BV1QA4m1F7t4/ 课程文档&#xff1a;Tutorial/huixiangdou/readme.md at camp2 InternLM/Tutorial GitHub 该课程&…

江苏开放大学2024年春《会计基础 050266》第二次任务:第二次过程性考核参考答案

电大搜题 多的用不完的题库&#xff0c;支持文字、图片搜题&#xff0c;包含国家开放大学、广东开放大学、超星等等多个平台题库&#xff0c;考试作业必备神器。 公众号 答案&#xff1a;更多答案&#xff0c;请关注【电大搜题】微信公众号 答案&#xff1a;更多答案&#…

记账本React案例(Redux管理状态)

文章目录 整体架构流程 环境搭建 创建项目 技术细节 一、别名路径配置 1.路径解析配置&#xff08;webpack&#xff09; &#xff0c;将/解析为src/ 2.路径联想配置&#xff08;vsCode&#xff09;&#xff0c;使用vscode编辑器时&#xff0c;自动联想出来src文件夹下的…

【java数据结构-优先级队列向下调整Topk问题,堆的常用的接口详解】

&#x1f308;个人主页&#xff1a;努力学编程’ ⛅个人推荐&#xff1a;基于java提供的ArrayList实现的扑克牌游戏 |C贪吃蛇详解 ⚡学好数据结构&#xff0c;刷题刻不容缓&#xff1a;点击一起刷题 &#x1f319;心灵鸡汤&#xff1a;总有人要赢&#xff0c;为什么不能是我呢 …

SCI一区级 | Matlab实现BES-CNN-GRU-Mutilhead-Attention多变量时间序列预测

SCI一区级 | Matlab实现BES-CNN-GRU-Mutilhead-Attention秃鹰算法优化卷积门控循环单元融合多头注意力机制多变量时间序列预测 目录 SCI一区级 | Matlab实现BES-CNN-GRU-Mutilhead-Attention秃鹰算法优化卷积门控循环单元融合多头注意力机制多变量时间序列预测预测效果基本介绍…
最新文章