Spring中如何优雅的使用策略模式
创作时间:
作者:
@小白创作中心
Spring中如何优雅的使用策略模式
引用
CSDN
1.
https://blog.csdn.net/weixin_46425661/article/details/140872043
策略模式是一种常用的设计模式,它允许系统在运行时选择不同的算法或行为。在Spring框架中,策略模式可以与依赖注入等特性完美结合,实现更加灵活和可扩展的系统设计。本文将详细介绍策略模式的概念、优缺点、使用场景,并通过具体的代码示例展示如何在Spring中实现策略模式。
一、策略模式是什么?
定义
策略模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户(满足开闭原则)。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。
结构
策略模式的主要角色如下:
- 抽象策略(Strategy)类:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
- 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现或行为。
- 环境(Context)类:持有一个策略类的引用,最终给客户端调用。
简单类图如下:
定义一个抽象策略(Strategy)类接口Strategy:
public interface Strategy {
void show();
}
定义具体策略角色(Concrete Strategy):
public class StrategyA implements Strategy {
public void show() {
System.out.println("StrategyA.show()");
}
}
//为中秋准备的促销活动B
public class StrategyB implements Strategy {
public void show() {
System.out.println("StrategyB.show()");
}
}
//为圣诞准备的促销活动C
public class StrategyC implements Strategy {
public void show() {
System.out.println("StrategyC.show()");
}
}
定义环境角色(Context)类SalesMan:
public class SalesMan {
//持有抽象策略角色的引用
private Strategy strategy;
public SalesMan(Strategy strategy) {
this.strategy = strategy;
}
//调用具体实现类
public void salesManShow(){
strategy.show();
}
}
客户端代码:
public class Client {
public static void main(String[] args) {
SalesMan salesMan = new SalesMan(new StrategyA());
salesMan.salesManShow();
System.out.println("==============");
salesMan.setStrategy(new StrategyB());
salesMan.salesManShow();
System.out.println("==============");
salesMan.setStrategy(new StrategyC());
salesMan.salesManShow();
}
}
二、策略模式的优缺点与使用场景
优缺点
优点:
- 策略类之间可以自由切换
由于策略类都实现同一个接口,所以使它们之间可以自由切换。 - 易于扩展
增加一个新的策略只需要添加一个具体的策略类即可,基本不需要改变原有的代码,符合“开闭原则“ - 避免使用多重条件选择语句(if else),充分体现面向对象设计思想。
缺点:
- 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
- 策略模式将造成产生很多策略类(可以通过使用享元模式在一定程度上减少对象的数量)
使用场景
- 一个系统需要动态地在几种算法中选择一种时,可将每个算法封装到策略类中。
- 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,可将每个条件分支移入它们各自的策略类中以代替这些条件语句。
- 系统中各算法彼此完全独立,且要求对客户隐藏具体算法的实现细节时。
- 系统要求使用算法的客户不应该知道其操作的数据时,可使用策略模式来隐藏与算法相关的数据结构。
- 多个类只区别在表现行为不同,可以使用策略模式,在运行时动态选择具体要执行的行为。
- 总之当出现如 if…else 语句、switch…case 语句时,就可以使用策略模式消除多重条件语句。
三、在Spring中使用策略模式
如现在有一个计算折扣的业务场景,并且需要动态的使用多种折扣策略计算。
1.抽象策略类
代码如下(示例):
import java.util.List;
import java.util.Map;
public interface DiscountService {
List getDiscountResult(Map<String, Object> params);
}
2.具体策略类
代码如下(示例):
import com.qbh.design.strategy.DiscountService;
import org.springframework.stereotype.Component;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@Component
public class DiscountAServiceImpl implements DiscountService {
@Override
public List getDiscountResult(Map<String, Object> params) {
//进行折扣相关业务处理
System.out.println("执行折扣A");
return Collections.emptyList();
}
}
@Component
public class DiscountBServiceImpl implements DiscountService {
@Override
public List getDiscountResult(Map<String, Object> params) {
//进行折扣相关业务处理
System.out.println("执行折扣B");
return Collections.emptyList();
}
}
@Component
public class DiscountCServiceImpl implements DiscountService {
@Override
public List getDiscountResult(Map<String, Object> params) {
//进行折扣相关业务处理
System.out.println("执行折扣C");
return Collections.emptyList();
}
}
3.环境类
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
@Component
public class DiscountContext {
//当一个接口有多个实现类时,Spring会自动将Strategy接口的实现类注入到这个Map中,key为bean id,value值则为对应的策略实现类
@Autowired
private Map<String, DiscountService> discountServiceMap;
/**
*
* @param key 实现类名
* @param params 参数
* @return
*/
public List execute(String key, Map<String, Object> params) {
DiscountService service = discountServiceMap.get(key);
return service.getDiscountResult(params);
}
}
在以上 DiscountContext 类中,Spring 会自动将 DiscountService 接口的实现类注入到discountServiceMap这个Map中。
前提是实现 DiscountService 接口的实现类得是交给Spring 容器管理的。
discountServiceMap的key值就是实现类的 bean id,也可以用@Component(“value”)的方式设置,像我上面直接用默认的方式的话,就是首字母小写。value值则为对应的策略实现类。
4.枚举
import cn.hutool.core.util.ObjectUtil;
public enum DiscountEnum {
strategyA("discountA", "discountAServiceImpl"),
strategyB("discountB", "discountBServiceImpl"),
strategyC("discountC", "discountCServiceImpl"),;
private String name;
private String discountImplName;
public static String getDiscountImplName(String name) {
if (ObjectUtil.isEmpty(name)) {
return null;
}
for (DiscountEnum aEnum : DiscountEnum.values()) {
if (aEnum.getName().equals(name)) {

return aEnum.getDiscountImplName();
}
}
return null;
}
DiscountEnum(String name, String discountImplName) {
this.name = name;
this.discountImplName = discountImplName;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDiscountImplName() {
return discountImplName;
}
public void setDiscountImplName(String discountImplName) {
this.discountImplName = discountImplName;
}
}
5.服务类
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class TestServiceImpl extends ServiceImpl<TestMapper, Test> implements ITestService {
@Autowired
private DiscountContext discountContext;
@Override
public void test(String name,Map<String, Object> params) {
discountContext.execute(DiscountEnum.getDiscountImplName(name),params);
}
}
本文原文来自CSDN
热门推荐
进击的巨人系列中最强的 9 大巨人
人民币韩元购买力
根除幽門螺旋杆菌:利大于弊?
孕妇吃撑了怎么办?4个实用缓解方法
两本新书聚焦脏话 试图回答为何骂人与怎么骂人的问题
研究:用植物性食物代替加工肉或红肉可降低患2型糖尿病的风险
帝国时代4兵种克制关系详解及运用技巧
检验小科普:何为空腹?
中国古代的珠算和算盘的发明
西方国家的庭院别墅中,最受欢迎的10种树,个个美轮美奂,各有特色
广东省发布按适宜生境绿化类型的树种选择
如何解决汽车门漏水问题以保护车内环境?常见的漏水原因有哪些?
诗王白居易的生平介绍
大量喝酒会导致视力下降吗
增值税发票使用指南:从开具到管理的全方位解析
电脑安装内存条后如何检查?安装内存条有哪些注意事项?
执子之手,与子偕老。诗经中最唯美的18句祝福语
小宝贝能做磁共振吗?儿童(婴幼儿)磁共振检查攻略
八卦掌之单换掌:每天15分钟,素人也能练出武侠高手的“内劲”!
天津国家海洋博物馆:中国唯一的国家级综合性海洋博物馆
松土精的使用方法及使用时的注意事项,有什么作用
儿童心理咨询师的岗位职责
“得中原者得天下”,这个中原到底指的哪里?是不是河南?
月食:月食多久一次?
华为笔记本电脑开不了机怎么办?试试这个办法
学术写作必备:用DOI快速查找和精准引用学术资料!
“棠”字的意思和解释,“棠”字的成语和组词
教师面试应该注意什么
相同额定容量电池包,为什么额定电压越大,续航越远?
郑和下西洋的目的解析