解锁Spring Boot中的设计模式—05.策略模式:探索【策略模式】的奥秘与应用实践!

1.策略者工厂模式(Map版本)

1.需求背景

假设有一个销售系统,需要根据不同的促销活动对商品进行打折或者其他形式的优惠。这些促销活动可以是针对不同商品类别的,比如男装、女装等。

2.需求实现
  1. 活动策略接口:定义了所有促销活动的公共接口,包括展示活动的方法。
  2. 具体策略活动:实现了活动策略接口的具体策略类,每个具体策略类代表一种促销活动,比如活动A和活动B。
  3. 连接策略的上下文:即环境角色,用于连接具体的促销活动和客户端。它持有一个策略对象,根据客户端的需求展示对应的活动。
  4. 策略工厂:提供了一种根据活动类型获取对应策略对象的方法,以便客户端根据需要选择促销活动。
3.策略者模式优点
  • 提供了对开闭原则的支持,可以灵活增加新的促销活动而无需修改现有代码。
  • 避免了使用多重条件语句,提高了代码的可读性和可维护性。
  • 可以方便地管理和组织相关的算法族,提高了代码的组织性和复用性。
4.策略者模式缺点
  • 客户端必须知道所有的策略类,并自行决定使用哪一个策略类,因此不适用于客户端不知道所有算法或行为的情况。
  • 可能会造成策略类的过多,每个具体策略类都会产生一个新类,增加了系统的复杂性。
5.应用场景
  • 当一个系统中存在多种相似但不同的算法或行为,并且需要动态切换时,可以考虑使用策略者模式。
  • 当需要在不修改现有代码的情况下灵活地增加新的算法或行为时,策略者模式也是一个不错的选择。

策略者模式在销售系统、支付系统、游戏开发等领域都有广泛的应用。

实现

1.1.具体策略活动
/*** 具体策略活动A*/
public class StrategyA implements Strategy {private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());@Overridepublic void show() {logger.error("活动A,减999!");}
}/*** 活动B*/
public class StrategyB implements Strategy {private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());@Overridepublic void show() {logger.error("活动B,减999999!");}
}
1.2.所有策略的公共接口
/*** 定义所有活动的公共接口*/
public interface Strategy {void show();}
1.3.连接策略的上下文
/*** 定义环境角色(Context):用于连接上下文,即把促销活动推销给客户,这里可以理解为销售员*/
public class ManStrategy {/*** 持有策略者角色的应用(传入啥执行啥)* SalesMan salesMan = new SalesMan(new StrategyA());* SalesMan salesManB = new SalesMan(new StrategyB());*/private Strategy strategy;/*** 初始化时 将具体的策略者 赋值给当前策略者引用* @param strategy*/public ManStrategy(Strategy strategy){this.strategy = strategy;}/*** 展示具体的策略*/public void showInfoStrategy(){strategy.show();}
}
1.4.策略工厂
public class HandlerStrategyFactory {private static final Map<String, Strategy> map = new HashMap<>();static {map.put("男装",new StrategyA());map.put("女装",new StrategyB());}public static Strategy getStrategy(String type){return map.get(type);}
}
1.5.测试
public class StrategyDemo {public static void main(String[] args) {// 对象模式ManStrategy manStrategy = new ManStrategy(new StrategyB());manStrategy.showInfoStrategy();// --------------------------- map集合 --------------------------// 根据对应各key 找到对应的实现类 然后执行对应方法 MAP集合 方式Strategy strategy = HandlerStrategyFactory.getStrategy("女装");strategy.show();}
}

在这里插入图片描述

2.策略工厂模式(Spring版本)

1. 简介

策略工厂模式是一种行为型设计模式,用于灵活选择不同算法,而不必改变代码结构。

2. 核心思想
  • 定义抽象策略接口和具体策略类。
  • 实现策略工厂,根据需求选择合适的策略类。
3. 案例背景

电商系统需要根据不同促销活动对商品进行打折,促销策略基于活动季节、产品类型等选择。

4. 示例要点
  • 定义抽象策略接口:PromotionStrategy,包含applyDiscount()方法。
  • 创建具体促销策略类如SpringFestivalPromotionMemberDayPromotion
  • 实现策略工厂PromotionStrategyFactory,根据需求选择合适的促销策略。
5. 应用场景
  • 需要根据不同条件选择合适算法。
  • 系统需要在不同环境下灵活切换算法。

策略工厂模式提供了灵活性和可维护性,使系统更加健壮。

2.1.类图

在这里插入图片描述

3.具体实现

3.1.抽象策略接口

/*** 抽象策略接口*/
public interface PromotionStrategy<R,T,U> {/*** 应用折扣* @param t 商品信息* @param u 用户信息* @return 折扣后的最终价格*/R applyDiscount(T t, U u);
}

3.2.策略具体实现类

3.2.1.春节促销策略实现类
package com.hrfan.java_se_base.pattern.strategy_pattern;import com.hrfan.java_se_base.log.model.UserInfoToken;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;import java.math.BigDecimal;/*** 春节促销 策略实现类*/
@Service
public class SpringFestivalPromotion implements PromotionStrategy<BigDecimal, String, UserInfoToken> {private final Logger logger = LoggerFactory.getLogger(SpringFestivalPromotion.class);/*** 春节折扣信息* @param goodsName 商品信息* @param userInfoToken 用户信息* @return*/@Overridepublic BigDecimal applyDiscount(String goodsName, UserInfoToken userInfoToken) {logger.error("============= {},春节大促销,原价100,现在6折 =============",goodsName);BigDecimal account = new BigDecimal("100");BigDecimal res = account.multiply(new BigDecimal("0.6")).setScale(2,BigDecimal.ROUND_HALF_UP);logger.error("============= 最终价格仅为:{},速来抢购! =============",res);return res;}
}
3.2.2.会员日策略实现类
package com.hrfan.java_se_base.pattern.strategy_pattern;import com.hrfan.java_se_base.log.model.UserInfoToken;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;import java.math.BigDecimal;/*** 会员日策略实现类*/
@Service
public class MemberDayPromotion implements PromotionStrategy<BigDecimal,String, UserInfoToken> {private final Logger logger = LoggerFactory.getLogger(MemberDayPromotion.class);/*** 会员日商品促销策略* @param goodsName 商品信息* @param userInfoToken 用户信息* @return 最终优惠后的价格*/@Overridepublic BigDecimal applyDiscount(String goodsName, UserInfoToken userInfoToken) {logger.error("============= {},会员日大促销,原价100,现在3折 =============",goodsName);BigDecimal account = new BigDecimal("100");BigDecimal res = account.multiply(new BigDecimal("0.3")).setScale(2,BigDecimal.ROUND_HALF_UP);logger.error("============= 最终价格仅为:{},速来抢购! =============",res);return res;}
}

3.3.创建策略工厂

import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;/*** 策略工厂*/
@Service
public class PromotionStrategyFactory {@Resourceprivate ApplicationContext context;/*** 选择对应的策略*/public PromotionStrategy createPaymentStrategy(String paymentMethod) {try {return context.getBean(paymentMethod, PromotionStrategy.class);}catch (Exception e){e.printStackTrace();throw new RuntimeException("未匹配到对应策略:" + paymentMethod);}}
}

4.测试

import com.hrfan.java_se_base.config.ResultObject;
import com.hrfan.java_se_base.log.model.UserInfoToken;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;
import java.math.BigDecimal;/*** 策略模式测试方法*/
@RestController
@RequestMapping("/v1/strategy/")
public class StrategyController {@Resourceprivate PromotionStrategyFactory promotionStrategyFactory;@PostMapping("/getLastPrice")public ResultObject getLastPrice(@RequestParam("type") String type, UserInfoToken userInfoToken){ResultObject instance = ResultObject.createInstance(true);// 获取商品的最终价格 (根据传入的策略然后选择对应的实现类 该type就是对应实现类的名称)PromotionStrategy strategy = promotionStrategyFactory.createPaymentStrategy(type);BigDecimal res = (BigDecimal) strategy.applyDiscount("鸡蛋", userInfoToken);instance.setData(res);instance.setMessage("获取成功!");return instance;}
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

策略工厂模式 vs 普通策略模式:区别总结

1. 概念
  • 策略工厂模式: 策略工厂模式是策略模式的一种变体,它将策略的选择和创建交给了工厂类来处理,客户端通过工厂获取需要的具体策略对象。
  • 普通策略模式: 普通策略模式直接由客户端选择和创建具体的策略对象,客户端需要明确知道每个策略类的存在,并负责创建相应的对象。
2. 结构
  • 策略工厂模式: 策略工厂模式包含策略接口、具体策略类和策略工厂类。客户端通过策略工厂类获取具体的策略对象。
  • 普通策略模式: 普通策略模式包含策略接口和具体策略类。客户端直接选择和创建具体的策略对象。
3. 使用场景
  • 策略工厂模式: 适用于需要根据条件选择不同策略,并且需要将策略选择逻辑与客户端分离的场景。适用于策略类较多,客户端不需要直接了解每个策略类的情况。
  • 普通策略模式: 适用于策略较少,客户端可以直接了解并选择每个策略类的情况。
4. 灵活性
  • 策略工厂模式: 策略工厂模式更加灵活,可以动态地切换策略,不需要修改客户端代码。
  • 普通策略模式: 普通策略模式相对固定,客户端需要显式地选择并创建具体的策略对象。
5. 维护性
  • 策略工厂模式: 策略工厂模式使得系统更易于扩展和维护,添加新的策略只需修改工厂类。
  • 普通策略模式: 普通策略模式需要客户端直接了解每个策略类,维护起来相对困难。
6. 总结
  • 策略工厂模式: 提供了更高的灵活性和可维护性,将策略的选择和创建与客户端分离。
  • 普通策略模式: 简单直接,适用于策略较少,且客户端能够明确选择每个策略类的情况。

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

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

相关文章

iPhone 16 组件泄露 揭示了新的相机设计

iPhone 16 的发布似乎已经等了很长一段时间&#xff0c;但下一个苹果旗舰系列可能会在短短 7 个月内与我们见面——而新的组件泄漏让我们对可能即将到来的重新设计有了一些了解。后置摄像头模块。 爆料者 Majin Bu&#xff08;来自 MacRumors&#xff09;获得的示意图显示&…

迅为3A5000_7A2000开发板龙芯自主指令系统支持PCIE3.0、USB3.0、SATA3.0、HDMI、VGA等

性能强 采用全国产龙芯3A5000处理器&#xff0c;基于龙芯自主指令系统 (LoongArch)的LA464微结构&#xff0c;并进一步提升频率&#xff0c;降低功耗&#xff0c;优化性能。 桥片 采用龙芯 7A2000&#xff0c;支持PCIE 3.0、USB 3.0和 SATA 3.0.显示接口2 路、HDMI 和1路 VGA…

Doris ——SQL原理解析

目录 前言 一、Doris简介 二、SQL解析简介 2.1 词法分析 2.2 语法分析 2.3 逻辑计划 2.4 物理计划 三、Doris SQL解析的总体架构 四、Parse阶段 五、Analyze阶段 六、SinglePlan阶段&#xff08;生成单机逻辑Plan阶段&#xff09; 七、DistributedPlan计划&#xf…

【大厂AI课学习笔记】【2.1 人工智能项目开发规划与目标】(5)数据管理

今天学习了数据管理&#xff0c;以及数据管理和数据治理的区别和联系。 数据管理&#xff1a;利用计算机硬件和软件技术对数据进行有效的收集、存储、处理和应用的过程其目的在于充分有效地发挥数据的作用。 实现数据有效管理的关键是数据组织。 数据管理和数据治理的区别&am…

【开源】SpringBoot框架开发智能教学资源库系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 课程档案模块2.3 课程资源模块2.4 课程作业模块2.5 课程评价模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 课程档案表3.2.2 课程资源表3.2.3 课程作业表3.2.4 课程评价表 四、系统展示五、核心代…

微服务—DSL基础语法与RestClient操作

本博客为个人学习笔记&#xff0c;学习网站&#xff1a;黑马程序员SpringCloud 2021教程 目录 DSL语法 索引库操作 mapping属性 创建索引库 字段拷贝 查询、删除、修改索引库 文档操作 新增文档 查询、删除文档 修改文档 全量修改 增量修改 DSL文档语法小结 Rest…

服务流控(Sentinel)

引入依赖 <!-- 必须的 --> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId> </dependency><!-- sentinel 核心库 --> <dependency><groupId>com.ali…

Spring 用法学习总结(四)之 JdbcTemplate 连接数据库

&#x1f409;目录 9 JdbcTemplate 9 JdbcTemplate Spring 框架对 JDBC 进行了封装&#xff0c;使用 JdbcTemplate 方便实现对数据库操作 相关包&#xff1a; 百度网盘链接https://pan.baidu.com/s/1Gw1l6VKc-p4gdqDyD626cg?pwd6666 创建properties配置文件 &#x1f4a5;注意…

如何使用python 挑战将ai生成的概念图制作成2d游戏

要使用Python将AI生成的概念图制作成2D游戏&#xff0c;你可以遵循以下步骤&#xff1a; 生成概念图&#xff1a; 使用AI图像生成工具&#xff08;如DALL-E、DeepArt等&#xff09;来创建你的游戏概念图。保存生成的图像文件&#xff0c;通常为PNG或JPEG格式。 选择游戏引擎&a…

STM32的三种下载方式

结果jlink&#xff0c;串口&#xff0c;stlink方式都没有问题&#xff0c;是当时缩减代码&#xff0c;看真正起作用的代码段有哪些&#xff0c;就把GPIO初始化中 /*开启GPIO外部时钟*/RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE); 把开启外部时钟的代码注释掉了。…

vue-路由(六)

阅读文章你可以收获什么&#xff1f; 1 明白什么是单页应用 2 知道vue中的路由是什么 3 知道如何使用vueRouter这个路由插件 4 知道如何如何封装路由组件 5 知道vue中的声明式导航router-link的用法 6 知道vue中的编程式导航的使用 7 知道声明式导航和编程式导航式如何传…

2024.2.15 模拟实现 RabbitMQ —— 消息持久化

目录 引言 约定存储方式 消息序列化 重点理解 针对 MessageFileManager 单元测试 小结 统一硬盘操作​​​​​​​ 引言 问题&#xff1a; 关于 Message&#xff08;消息&#xff09;为啥在硬盘上存储&#xff1f; 回答&#xff1a; 消息操作并不涉及到复杂的增删查改消…

MIT-BEVFusion系列八--onnx导出2 spconv network网络导出

这里写目录标题 export-scn.py加载模型设置每层的精度属性初始化输入参数导出模型model.encoder_layers 设置初始化参数设置 indice_key 属性更改 lidar backbone 的 forward更改lidar网络内各个层的forward带参数装饰器&#xff0c;钩子函数代码使用装饰器修改forward举例 跟踪…

Codeforces Round 926 (Div. 2)

C:Sasha and the Casino 类似于倍投法&#xff0c;就是在一赔一的情况下,第一次压一块钱,每输一次就押注上一次两倍的金额. 假如资金无限的话,这种方法赢的期望为无穷大.原理类似于二进制&#xff0c;不论你输再多次,只要赢一次总额就增加了1.比如 15 二进制1111&#xff0c;…

【嵌入式】校招信息表(持续更新)

相关文章 写一份让HR过目不忘的简历 嵌入式校招信息表 一、校招信息表二、注意事项三、最后 一、校招信息表 二、注意事项 三、最后 【校招】如何写出HR最喜欢的简历&#xff0c;一个视频讲清楚

CTFshow web(php文件上传155-158)

web155 老样子&#xff0c;还是那个后端检测。 知识点&#xff1a; auto_append_file 是 PHP 配置选项之一&#xff0c;在 PHP 脚本执行结束后自动追加执行指定的文件。 当 auto_append_file 配置被设置为一个文件路径时&#xff0c;PHP 将在执行完脚本文件的所有代码后&…

如何减少HTTP请求次数

资料来源 : 小林coding 小林官方网站 : 小林coding (xiaolincoding.com) 如何减少HTTP请求次数? 减少 HTTP 请求次数自然也就提升了 HTTP 性能&#xff0c;可以从这 3 个方面入手: 减少重定向请求次数合并请求延迟发送请求 减少重定向请求次数 我们先来看看什么是重定向请…

第6个-滚动动画

Day 6 - Scroll Animation 1. 演示效果 2. 分析思路 布局 所有的内容进行水平垂直居中&#xff0c;可以使用**margin:0 auto;&#xff0c;也可以使用flex**布局&#xff1a; body {background-color: #efedd6;display: flex;flex-direction: column;justify-content: center…

【C++】C++11上

C11上 1.C11简介2.统一的列表初始化2.1 {} 初始化2.2 initializer_list 3.变量类型推导3.1auto3.2decltype3.3nullptr 4.范围for循环5.final与override6.智能指针7. STL中一些变化8.右值引用和移动语义8.1左值引用和右值引用8.2左值引用与右值引用比较8.3右值引用使用场景和意义…

HarmonyOS—@State装饰器:组件内状态

State装饰的变量&#xff0c;或称为状态变量&#xff0c;一旦变量拥有了状态属性&#xff0c;就和自定义组件的渲染绑定起来。当状态改变时&#xff0c;UI会发生对应的渲染改变。 在状态变量相关装饰器中&#xff0c;State是最基础的&#xff0c;使变量拥有状态属性的装饰器&a…