设计模式之基于SpringBoot项目实现策略模式
1. 使用场景
1)如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
2)一个系统需要动态地在几种算法中选择一种。
3)如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
2. 三个核心角色
1)环境(Context):维护一个对策略对象的引用,负责将客户端请求委派给具体的策略对象执行。环境类可以通过依赖注入、简单工厂等方式来获取具体策略对象。
2)抽象策略(Abstract Strategy):定义了策略对象的公共接口或抽象类,规定了具体策略类必须实现的方法。
3)具体策略(Concrete Strategy):实现了抽象策略定义的接口或抽象类,包含了具体的算法实现。
3. 实现方法
策略模式通过将算法与使用算法的代码解耦,提供了一种动态选择不同算法的方法。客户端代码不需要知道具体的算法细节,而是通过调用环境类来使用所选择的策略。
1)一系列具体策略类(Concrete Strategy)继承同一个抽象策略接口或者抽象类(Abstract Strategy),
2)环境类(Context) 中将抽象策略接口或者抽象类(Abstract Strategy)的对象定义为成员变量,并动态为该变量赋值为某一个具体策略类(Concrete Strategy),
3)在使用该变量调用**抽象策略接口或者抽象类(Abstract Strategy)**中的方法,获得返回结果。
4. 代码思路
使用场景:
在一个购物网站中,不同类型的用户可以享受不同的折扣。
假设现在有两种用户,普通用户(Normal)和VIP用户(VIP),
普通用户没有折扣,应付金额 = 订单金额,
VIP客户可以享受八折,应付金额 = 订单金额 * 0.8
代码思路:
新建折扣策略接口 DiscountStrategy ,定义计算应付金额的方法 calculatePayAmount()
新建普通用户折扣策略类和VIP用户折扣策略类,继承折扣策略接口 DiscountStrategy,并实现对应的方法 calculatePayAmount()
新建环境类(Context) ,定义一个折扣策略接口 DiscountStrategy 类型的变量 discountStrategy ,
定义方法calculatePayAmount(),根据不同的条件将discountStrategy 赋值为具体的策略类对象
在controller层和service层调用环境类(Context) 的该方法calculatePayAmount()
5. 代码实现
DiscountStrategy 接口
package com.hsh.strategydemo.strategy;
import org.springframework.stereotype.Component;
/**
* @Author hsh
* @DateTime 2023/08/07 23:20
**/
public interface DiscountStrategy {
/**
* 根据用户类型和总金额,计算出应付金额
* @param totalAmount
* @param userType
* @return
*/
double calculatePayAmount(double totalAmount, String userType);
}
普通用户折扣策略类
package com.hsh.strategydemo.strategy.impl;
import com.hsh.strategydemo.strategy.DiscountStrategy;
import org.springframework.stereotype.Component;
/**
*
* @Author hsh
* @DateTime 2023/08/07 23:21
**/
@Component
public class NormalDiscountStrategy implements DiscountStrategy {
/**
* 根据用户类型和总金额,计算出应付金额
* @param totalAmount
* @param userType
* @return
*/
@Override
public double calculatePayAmount(double totalAmount, String userType) {
return totalAmount;
}
}
VIP用户折扣策略类
package com.hsh.strategydemo.strategy.impl;
import com.hsh.strategydemo.strategy.DiscountStrategy;
import org.springframework.stereotype.Component;
/**
* @Author hsh
* @DateTime 2023/08/07 23:35
**/
@Component
public class VIPDiscountStrategy implements DiscountStrategy {
/**
* 根据用户类型和总金额,计算出应付金额
* @param totalAmount
* @param userType
* @return
*/
@Override
public double calculatePayAmount(double totalAmount, String userType) {
return totalAmount * 0.8;
}
}
context类
package com.hsh.strategydemo.context;
import com.hsh.strategydemo.strategy.DiscountStrategy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* 上下文类
* @Author hsh
* @DateTime 2023/08/07 23:39
**/
@Component
public class DiscountStrategyContext {
//获得实现该接口的所有实现类对象的集合,对象名称为键,对象为值
@Autowired
private Map<String, DiscountStrategy> discountStrategyMap;
//将策略借口作为属性
private DiscountStrategy discountStrategy;
public double calculatePayAmount(double totalAmount, String userType) throws Exception {
//根据相关条件选择对应的策略类对象,条件复杂时也可以用if-else-else if代替
switch (userType){
case "Normal":
discountStrategy = discountStrategyMap.get("normalDiscountStrategy") ;
break;
case "VIP":
discountStrategy = discountStrategyMap.get("VIPDiscountStrategy") ;
break;
default:
throw new Exception("没有该类型的用户");
}
return discountStrategy.calculatePayAmount(totalAmount, userType);
}
}
controller类
package com.hsh.strategydemo.controller;
import com.hsh.strategydemo.context.DiscountStrategyContext;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.websocket.server.PathParam;
/**
* @Author hsh
* @DateTime 2023/08/07 23:31
**/
@RestController
public class PayController {
@Resource
private DiscountStrategyContext discountStrategyContext;
@GetMapping("/pay")
public String pay(double totalAmount, String userType) throws Exception {
double payAmount = discountStrategyContext.calculatePayAmount(totalAmount, userType);
return "应付金额为:"+payAmount;
}
}
参数:
totalAmount:10.0
userType:VIP
构建url:
localhost:8080/pay?totalAmount=10.0&userType=VIP
预计返回:
应付金额为:8.0
实际访问结果:

本文详细介绍了在SpringBoot项目中如何应用策略模式,包括使用场景、三个核心角色(环境、抽象策略和具体策略)、实现方法以及一个实际的折扣策略计算例子。展示了如何通过策略模式动态切换算法,提高代码的灵活性和可扩展性。

2万+

被折叠的 条评论
为什么被折叠?



