对策略模式的理解

目录

  • 一、场景
    • 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;@Overridepublic void execute(Integer data) {System.out.println((int) (data * discount));}
}public class FullMinusStrategy implements Strategy<Integer> {@Overridepublic 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;@Overridepublic boolean match(Integer matchContext) {return matchContext == 1;}@Overridepublic void execute(Integer data) {System.out.println((int) (data * discount));}
}public class FullMinusStrategy implements Strategy<Integer, Integer> {@Overridepublic boolean match(Integer matchContext) {return matchContext == 2;}@Overridepublic 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 {@Autowiredprivate 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 {// 字段注入,不支持静态变量。@Autowiredprivate static List<Strategy> strategies;...
}

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

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

相关文章

2024年Q1企业邮箱安全性研究报告:钓鱼邮件同比增长59.9%

4月23日&#xff0c;Coremail邮件安全联合北京中睿天下信息技术有限公司发布《2024年第一季度企业邮箱安全性研究报告》。对当前企业邮箱的应用状况和安全风险进行了分析。 1、垃圾邮件持续增长 根据Coremail邮件安全人工智能实验室最新数据显示&#xff0c;2024年第一季度&am…

4 -26

4-26 1 英语单词100个一篇六级翻译 2 div 4 补题目 3 概率论期中卷子一张&#xff0c;复习复习。 4 备课ing 晚上出去炫饭&#xff0c;串串香&#xff0c;无敌了。 中间一些模拟题是真的恶心&#xff0c;思维题是真的想不到&#xff0c;感觉自己就是一个废物呢。 1.是将一个数…

[C++]STL---unordered_set与unordered_map的模拟实现

目录 前言 哈希桶的改造 哈希桶的初步改造 迭代器的模拟实现 operator() 类互相typedef时的前置声明 友元声明 迭代器的出口 插入Insert() 查找Find(&#xff09; 哈希表的最终改造 unordered_set的模拟实现 unordered_map的模拟实现 前言 unordered_set与set的区…

mysql索引里得基数是啥

最近遇到又问mysql索引中得基数是啥&#xff0c;有什么影响吗&#xff0c;下面罗列以下&#xff1a; 索引里得基数是指索引中存放得不同值的数量。对于像某个字段&#xff0c;如果存有多个不同的值&#xff0c;那么基数就会大&#xff0c;反之&#xff0c;如果有很多重复的值&a…

运行游戏提示dll文件丢失,分享多种有效的解决方法

在我们日常频繁地利用电脑进行娱乐活动&#xff0c;特别是畅玩各类精彩纷呈的电子游戏时&#xff0c;常常会遭遇一个令人困扰的问题。当我们满怀期待地双击图标启动心仪的游戏程序&#xff0c;准备全身心投入虚拟世界时&#xff0c;屏幕上却赫然弹出一条醒目的错误提示信息&…

最受站长欢迎的wordpress模板

蓝色与黄色&#xff0c;作为经典的互补色&#xff0c;它们在企业网站设计中总能碰撞出令人印象深刻的火花。当这两种鲜艳的色彩巧妙结合时&#xff0c;不仅能够吸引访客的注意力&#xff0c;还能传达出一种活力四射、积极向上的企业形象。 今天&#xff0c;我们为您推荐的这款…

LAPGAN浅析

LAPGAN 引言 在原始 GAN和CGAN中&#xff0c;还只能生成 16*16, 28*28, 32*32 这种低像素小尺寸的图片。而LAPGAN首次实现 64*64 的图像生成。与其一下子生成这么大的图像 &#xff08;包含信息量这么多&#xff09;&#xff0c;不如一步步由小到大&#xff0c;这样每一步生成…

书籍推推荐之二--《生命的色彩》

史钧《生命的色彩》 在生活中&#xff0c;我们会注意到一个有趣的现象&#xff1a;每个人的头发颜色各不相同&#xff0c;有黑色、灰色、黄色、棕红色、银白色等&#xff0c;但就是没有绿色。对于生活在丛林中的早期人类来说&#xff0c;绿色的头发简直就是天然的迷彩服&#x…

RabbitMq总结

1.架构 rabbitmq由消费者&#xff0c;生产者&#xff0c;交换机&#xff0c;队列&#xff0c;bindingkey组成&#xff0c;交换机存在四种&#xff0c;主流使用三种 2.事务消息机制 将消息发送到一个单独的事务队列&#xff0c;再从事务队列发送到消费者可消费的队列&#xf…

区块链在物流中的应用

区块链如何在物流行业中应用&#xff1f; - 知乎 (zhihu.com) 区块链物流:打造智能物流可信生态网络 - 知乎 (zhihu.com) 菜鸟供应链发布一款基于大模型的数字化供应链产品“天机π”&#xff0c;通过菜鸟算法基于大模型的生成式AI辅助决策&#xff0c;在销量预测、补货计划和…

随手记:树结构翻页和定位指定数据逻辑

业务背景&#xff1a; 树形组件展示数据&#xff0c;数据包含过去数据&#xff0c;现在数据&#xff0c;未来数据&#xff0c;用户在首次进入页面时&#xff0c;展示的是当天的数据&#xff0c;如果当天没有数据&#xff0c;则显示最近一条的过去数据。数据按照时间越长数据会…

《托斯卡纳艳阳》

有爱情不断流淌的地方&#xff0c;当然充满了诱惑。这里最迷人而优雅的桥段&#xff0c;是非常绅士而浪漫内心丰盈又恪守道德的男人马蒂尼&#xff08;好评&#xff09;赶来为女主捉蛇。蛇的设定自然源于亚当夏娃&#xff0c;而蛇的就此消失&#xff0c;当然告诉我们浪漫不代表…

可替代IBM DOORS的现代化需求管理解决方案Jama Connect,支持数据迁移及重构、实时可追溯性、简化合规流程

作为一家快速发展的全球性公司&#xff0c;dSPACE一直致力于寻找保持领先和优化开发流程的方法。为推进其全球现代化计划&#xff0c;dSPACE开始寻找可以取代传统需求管理平台&#xff08;IBM DOORS&#xff09;的需求管理解决方案。 通过本次案例&#xff0c;您将了解dSPACE为…

大数据第五天(操作hive的方式)

文章目录 操作hive的方式hive 存储位置hive 操作语法创建数据表的方式 操作hive的方式 hive 存储位置 hive 操作语法 创建数据表的方式 – 创建数据库 create database if not exists test我们创建数据库表的时候&#xff0c;hive是将我们的数据自动添加到数据表中&#xf…

江苏开放大学2024年春《机电设备安装与调试 050095》第三次形成性考核作业参考答案

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

一文解析golang中的协程与GMP模型

文章目录 前言1、线程实现模型1.1、用户级线程与内核级线程1.2、内核级线程模型1.3、用户级线程模型1.3、两级线程模型 2、GMP模型2.1、GMP模型概述2.1、GMP v1版本 - GM模型2.2、GMP v2版本 - GMP模型2.3、GMP相关源码2.4 调度流程2.5 设计思想 3.总结 前言 并发(并行&#x…

vue实现录音并转文字功能,包括PC端web,手机端web

vue实现录音并转文字功能&#xff0c;包括PC端&#xff0c;手机端和企业微信自建应用端 不止vue&#xff0c;不限技术栈&#xff0c;vue2、vue3、react、.net以及原生js均可实现。 原理 浏览器实现录音并转文字最快捷的方法是通过Web Speech API来实现&#xff0c;这是浏览器…

look-behind requires fixed-width pattern_正则表达式

问题&#xff1a;例如我想要匹配一段文本中&#xff0c;字符“a”在“小猫”的前面&#xff0c;中间有可能间隔好几个字符&#xff0c;也有可能直接相邻。结果只返回“小猫”。 import re text "这是一只非常可爱的a的的小猫." pattern r"(?<a*)小猫"…

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;例如器件识别&…

淘宝/天猫按图搜索淘宝商品(拍立淘) API,按图搜索商品详情

淘宝/天猫的“按图搜索商品”功能&#xff0c;通常被称为“拍立淘”&#xff0c;允许用户通过上传图片来搜索相似的商品。这项服务背后是由淘宝提供的API支持&#xff0c;使得用户能够快速找到与上传图片相匹配或类似的商品。以下是关于“按图搜索淘宝商品”API的一些关键信息&…