解锁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.hqwc.cn/news/474236.html

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

相关文章

后端学习:Maven模型与Springboot框架

Maven 初识Maven Maven:是Apache旗下的一个开源项目&#xff0c;是一款用于管理和构建java项目的工具。 Maven的作用1.依赖管理2.统一项目结构3.项目构建依赖管理&#xff1a;方便快捷的管理项目依赖的资源(jar包)&#xff0c;避免版本冲突问题   当使用maven进行项目依赖…

【教学类-19-10】20240214《ABAB式-规律黏贴18格-手工纸15*15CM-一页3种图案,AB一组样板,纵向、有边框》(中班)

背景需求 利用15*15CM手工纸制作AB色块手环&#xff08;手工纸自带色彩&#xff09;&#xff0c;一页3个图案&#xff0c;2条为一组&#xff0c;画图案&#xff0c;黏贴成一个手环。 素材准备 代码展示 # # 作者&#xff1a;阿夏 # 时间&#xff1a;2024年2月14日 # 名称&…

19-k8s的附加组件-coreDNS组件

一、概念 coreDNS组件&#xff1a;就是将svc资源的名称解析成ClusterIP&#xff1b; kubeadm部署的k8s集群自带coreDNS组件&#xff0c;二进制部署需要自己手动部署&#xff1b; [rootk8s231 ~]# kubectl get pods -o wide -A k8s系统中安装了coreDNS组件后&#xff0c;会有一个…

BuildAdmin - 免费开源可商用!基于 ThinkPHP8 和 Vue3 等流行技术栈打造的商业级后台管理系统

一款包含 PHP 服务端和 Vue 前端代码的 admin 管理系统&#xff0c;实用性很强&#xff0c;推荐给大家。 BuildAdmin 是一个成熟的后台管理系统&#xff0c;后端服务采用 ThinkPHP8 &#xff0c;数据库使用 Mysql&#xff0c;前端部分则使用当前流行的 Vue3 / TypeScript / Vi…

K8s进阶之路-安装部署K8s

参考&#xff1a;&#xff08;部署过程参考的下面红色字体文档链接就可以&#xff0c;步骤很详细&#xff0c;重点部分在下面做了标注&#xff09; 安装部署K8S集群文档&#xff1a; 使用kubeadm方式搭建K8S集群 GitBook 本机&#xff1a; master&#xff1a;10.0.0.13 maste…

Vulnhub靶场 DC-6

目录 一、环境搭建 二、主机发现 三、漏洞复现 1、wpscan工具 2、后台识别 dirsearch 3、爆破密码 4、rce漏洞利用 activity monitor 5、rce写shell 6、新线索 账户 7、提权 8、拿取flag 四、总结 一、环境搭建 Vulnhub靶机下载&#xff1a; 官网地址&#xff1a…

stable diffusion webui学习总结(2):技巧汇总

一、脸部修复&#xff1a;解决在低分辨率下&#xff0c;脸部生成异常的问题 勾选ADetailer&#xff0c;会在生成图片后&#xff0c;用更高的分辨率&#xff0c;对于脸部重新生成一遍 二、高清放大&#xff1a;低分辨率照片提升到高分辨率&#xff0c;并丰富内容细节 1、先通过…

springboot登录校验

一、登录功能 二、登录校验 2.1 会话技术 2.2 JWT令牌 JWT令牌解析&#xff1a; 如何校验JWT令牌&#xff1f;Filter和Interceptor两种方式。 2.3 过滤器Filter 2.3.1 快速入门 修改上述代码&#xff1a; 2.3.2 详解 2.3.3 登录校验-Filter 2.4 Interceptor拦截器 2.4.1 …

多线程---线程同步,线程通信

线程同步 1.概述 线程同步是多线程编程中的一个重要概念&#xff0c;它指的是在多线程环境中&#xff0c;通过一定的机制保证多个线程按照某种特定的方式正确、有序地执行。这主要是为了避免并发问题&#xff0c;如死锁、竞态条件、资源争用等&#xff0c;确保数据的一致性和完…

MySQL数据库进阶第一篇(存储引擎与Linux系统上安装MySQL数据库)

文章目录 一、MySQL体系结构二、存储引擎介绍相关操作&#xff1a; 三、InnoDB 存储引擎简介四、MyISAM 存储引擎简介五、Memory 存储引擎简介六、存储引擎特点七、存储引擎的选择八、Linux系统上安装MySQL数据库1.用FinalShell远程连接Linux系统2.下载Linux版的MySQL安装包3.上…

蓝桥杯备赛_python_BFS搜索算法_刷题学习笔记

1 bfs广度优先搜索 1.1 是什么 1.2怎么实现 2案例学习 2.1.走迷宫 2.2.P1443 马的遍历 2.3. 九宫重排&#xff08;看答案学的&#xff0c;实在写不来&#xff09; 2.4.青蛙跳杯子&#xff08;学完九宫重排再做bingo&#xff09; 2.5. 长草 3.总结 1 bfs广度优先搜索 【P…

模拟算法.

1.什么是模拟 在信息奥赛中,有一类问题是模拟一个游戏的对弈过程或者模拟一项任务的操作过程.比如乒乓球在比赛中模拟统计记分最终判断输赢的过程等等,这些问题通常很难通过建立数学模型用特定的算法来解决因为它没有一种固定的解法,需要深刻理解出题者对过程的解释一般只能采…