⭐简单说两句⭐
✨ 正在努力的小新~
💖 超级爱分享,分享各种有趣干货!
👩💻 提供:模拟面试 | 简历诊断 | 独家简历模板
🌈 感谢关注,关注了你就是我的超级粉丝啦!
🔒 以下内容仅对你可见~作者:不正经小新,CSDN后端领域新星创作者 |阿里云专家博主
CSDN个人主页:不正经小新
🔎GZH:
不正经小新
🎉欢迎关注🔎点赞👍收藏⭐️留言📝

👻1 看了脑瓜子疼的概念
老板们,我们先来看下在维基百科上面说的概念:
策略模式作为一种软件设计模式,指对象有某个行为 ,但是在不同的场景中,该行为有不同的实现算法。你是一个演员,每天要根据不同的剧本扮演不同的角色。这就是策略模式,你的表演技巧就是那些算法,而每个角色就是不同的场景。
策略模式
- 定义了一族算法(业务规则);
- 封装了每个算法;
- 这族的算法可互换代替(interchangeable)
💬【Tips】 这段话的来源是:维基百科
💬【Tips】 因为这个面向业务开发,所以需要具备Java基础和Spring框架的基础额~
💬【Tips】 本文的具体业务逻辑并没有实现,是通过打印日志假装实现的额(重点在于理解策略模式),老板们阔以自行发挥~
🥰2 可爱的产品经理提需求了
产品经理: 这个小可爱,来对接下需求~
小可爱: 我手上的需求都没做完呢,你又来什么需求?
产品经理: 很简单,就是我们的用户忘记密码了,要找回密码,可以让用户选择不同的方式,比如:手机验证码验证、密保问题验证,就先做这两个吧~
小可爱: 不行,得加钱
产品经理: 哎呀,少废话,赶紧做,下午给你买杯咖啡
🤪3 憨憨的你框框堆💩代码(未用策略模式)
想要快点喝到美味咖啡的你,打开你的IDE后,经过几秒的思考后,说,这还不简单~
我们定义一个接口,通过一个枚举参数来判断是发送短信还是APP弹窗噻,写两个If判断不就OK了么~
随后你便框框的敲上了代码~
先说说这个堆山版本的总体思路
- 定义枚举类VerifyEnums和请求参数
- controller层代码(请求入口)
- service层代码(模拟实现)
VerifyEnums枚举类 代码清单
public enum VerifyEnums {
/**
* 手机验证码
*/
PHONE("phone", "手机验证码"),
/**
* 密保问题验证
*/
CONFIDENTIAL("confidential", "密保问题验证")
;
private final String type;
private final String desc;
VerifyEnums(String type, String desc) {
this.type = type;
this.desc = desc;
}
}
VerifyParam 代码清单
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class VerifyParam {
/**
* 用户名
*/
private String userName;
/**
* 用户ID
*/
private String userId;
/**
* 手机号
*/
private String phoneNumber;
/**
* 密保问题和答案 - 这里简单处理
*/
private JSONObject questionAndAnswer;
/**
* 验证类型
*/
private String verifyType;
}
PhoneService手机验证码服务 代码清单
@Service
@Slf4j
public class PhoneService {
public String verify(VerifyParam param) {
//校验
Assert.isTrue(StringUtils.isNotEmpty(param.getUserId()), "用户ID不能为空");
Assert.isTrue(StringUtils.isNotEmpty(param.getPhoneNumber()), "手机号不能为空");
// 业务逻辑
log.info("进行手机号验证码验证逻辑~");
// 这里简单处理,直接返回
return "手机验证码验证成功";
}
}
ConfidentialService密保问题服务 代码清单
@Service
@Slf4j
public class ConfidentialService {
public String verify(VerifyParam param) {
//校验
Assert.isTrue(StringUtils.isNotEmpty(param.getUserId()), "用户ID不能为空");
Assert.isTrue(MapUtils.isNotEmpty(param.getQuestionAndAnswer()), "手机号不能为空");
// 业务逻辑
log.info("进行密保问题验证逻辑~");
// 这里简单处理,直接返回
return "密保问题验证成功";
}
}
VerifyService验证Service 代码清单
@Service
@Slf4j
@RequiredArgsConstructor
public class VerifyService {
private final PhoneService phoneService;
private final ConfidentialService confidentialService;
public String verify(VerifyParam param) {
String verifyType = param.getVerifyType();
if (StringUtils.equals(VerifyEnums.PHONE.getType(), verifyType)) {
return phoneService.verify(param);
}
if (StringUtils.equals(VerifyEnums.CONFIDENTIAL.getType(), verifyType)) {
return confidentialService.verify(param);
}
return "验证失败,请重试~";
}
}
VerifyController验证控制类 代码清单
@RestController
@RequiredArgsConstructor
@RequestMapping("v1/reset")
public class VerifyController {
private final VerifyService verifyService;
@PostMapping("verify")
public String verify(@RequestBody VerifyParam param) {
return verifyService.verify(param);
}
}
OK OK 齐活了
运行SpringBoot项目
我们到apifox这个软件中运行(apifox是API 文档、API 调试、API Mock、API 自动化测试一体化协作平台,推荐大家可以使用下,使用起来感觉还不错~)
后台的日志
可以看到验证成功,我们更换verifyType也可以得到对应的结果,友友们可以自己尝试下~
哐哐哐,写完了,咖啡也到了,喝了一小口咖啡,觉得生活美滋滋啊~
产品经理: 可就当你咖啡喝了一小口,产品经理过来了~
产品经理: 你再加一个功能,让用户还可以通过邮箱验证的方式进行密码找回~
小可爱: 啊,你刚刚为什么不说啊,都写完了
产品经理对你进行了一顿猛夸~,你听着这夸赞心里乐开花了,便接下了这活
你在枚举中添加了一个邮箱验证的枚举
然后你又写了一个MailService
在VerifyService
中又加了个if语句
写完测试通过后,感觉美滋滋
但是看着这不断增加的if语句,心里很不是个滋味💔
🤓4 聪明的你决定设计一个优雅的代码
写完代码的你,刷到一条励志鸡汤,然后你像是下定了某种决心,决定开始重构这个代码~
你在网上查询大量资料后,发现有个设计模式可以很好的解决你这个问题~
这个设计模式就是:策略模式
于是乎,你便开始使用策略模式进行重构你的Java代码
重构思路
- 定义一个策略接口
- 具体实现类去实现策略接口
- 定义一个工厂类,这个工厂能够通过实现类在Spring的Ioc容器中的名称来获取实例
- VerifyService中调用工厂类的方法获取具体的策略实现类,然后调用验证方法
VerifyStrategy策略接口 代码清单
public interface VerifyStrategy<T> {
String verify(T param);
}
PhoneServiceYes具体策略实现类 代码清单
@Service(value = "phoneStrategy")
@Slf4j
public class PhoneServiceYes implements VerifyStrategy<VerifyParam> {
@Override
public String verify(VerifyParam param) {
//校验
Assert.isTrue(StringUtils.isNotEmpty(param.getUserId()), "用户ID不能为空");
Assert.isTrue(StringUtils.isNotEmpty(param.getPhoneNumber()), "手机号不能为空");
// 业务逻辑
log.info("进行手机号验证码验证逻辑~");
// 这里简单处理,直接返回
return "手机验证码验证成功";
}
}
ConfidentialServiceYes 具体策略实现类 代码清单
@Service("confidentialStrategy")
@Slf4j
public class ConfidentialServiceYes implements VerifyStrategy<VerifyParam> {
@Override
public String verify(VerifyParam param) {
//校验
Assert.isTrue(StringUtils.isNotEmpty(param.getUserId()), "用户ID不能为空");
Assert.isTrue(MapUtils.isNotEmpty(param.getQuestionAndAnswer()), "手机号不能为空");
// 业务逻辑
log.info("进行密保问题验证逻辑~");
// 这里简单处理,直接返回
return "密保问题验证成功";
}
}
【Tips】可能细心的老板发现了一个东西,就是我们的Service注解中多了一个东西,这里解释下~
其实稍微有点Spring框架的基础的老板是能看懂的,这里涅,顺带给各位老板复习下,哈哈哈~
@Service(“confidentialStrategy”) 它用于将类标记为Spring的服务Bean,并为其指定一个名称。它告诉Spring容器这个类是一个服务,应该被实例化并管理为一个Bean。
在我们的代码中,@Service(“confidentialStrategy”) 注解将 ConfidentialServiceYes 类标记为一个名为 “confidentialStrategy” 的服务Bean。这样,在其他地方需要使用这个服务时,可以通过这个名称来获取它的实例。
例如,可以在其他类中使用 @Resource 注解来自动注入这个Bean
StrategyFactory 工厂 代码清单
@Component
@SuppressWarnings("unchecked")
public class StrategyFactory {
@Resource
private ApplicationContext applicationContext;
/***
* 获取策略
* @param type 类型
* @return 策略
*/
public <T> VerifyStrategy<T> getStrategy(String type) {
return applicationContext.getBean(type + "Strategy", VerifyStrategy.class);
}
}
这里给大家解释下这个工厂类~
这个类是一个策略工厂,用于根据不同的类型获取相应的策略实例。以下是对这个类的详细解释:
- @Component 注解: 这是一个Spring框架中的注解,用于将类标记为Spring的组件,使其能够被Spring容器识别和管理。
- @SuppressWarnings("unchecked") 注解: 这个注解用于抑制编译器警告,通常用于告诉编译器忽略特定类型的警告。在这个例子中,它可能是用来忽略与泛型相关的警告。
- @Resource 注解: 这是一个Java EE和Spring框架中的注解,用于将Spring容器中的Bean注入到当前类的字段中。在这个例子中,applicationContext 字段被标记为 @Resource,这意味着Spring容器将自动注入一个 ApplicationContext 实例到这个字段中。
- getStrategy 方法: 这是一个泛型方法,用于根据传入的类型参数获取相应的策略实例。方法的参数是一个字符串 type,表示策略的类型。方法的返回值是一个 VerifyStrategy 类型的实例,其中 T 是一个泛型参数,表示策略处理的数据类型。
- applicationContext.getBean(type + "Strategy", VerifyStrategy.class): 这行代码使用Spring的 ApplicationContext 来获取一个Bean实例。type + "Strategy" 是要获取的Bean的名称,VerifyStrategy.class 是要获取的Bean的类型。Spring将根据这些信息从容器中查找并返回相应的Bean实例。
这个策略工厂类的主要作用是提供一个统一的接口,用于根据不同的类型获取相应的策略实例,从而实现策略模式。
VerifyService类中添加一个方法
public String verifyYes(VerifyParam param) {
String verifyType = param.getVerifyType();
VerifyStrategy<VerifyParam> strategy = strategyFactory.getStrategy(verifyType);
String verify = strategy.verify(param);
if (StringUtils.isNotEmpty(verify)) {
return verify;
}
return "验证失败,请重试~";
}
VerifyController中对应添加一个方法
@PostMapping("verifyYes")
public String verifyYes(@RequestBody VerifyParam param) {
return verifyService.verifyYes(param);
}
好了,齐活,运行看结果
如果后面产品经理在加其他需求的话,
- 我们只需要在
VerifyEnums
枚举中添加一种类型 - 然后在写一个具体的实现类
对比下下~
哪个优雅哪个帅气各位老板们肯定有数吧,哈哈哈🤓🤓🤓
类图如下
☘️5 谈谈优点和缺点
优点:
-
可替换性:策略模式使得算法可以相互替换,而不需要修改使用算法的代码。
-
可扩展性:新增策略时,只需添加新的策略类,无需修改现有代码,符合开闭原则。
-
解耦:策略模式将算法的具体实现与使用算法的上下文分离,降低了系统的耦合度。
-
复用性:由于算法被封装在独立的策略类中,可以在不同的上下文中复用这些策略。
-
减少条件判断:策略模式可以减少代码中的if-else或switch-case等条件判断,使代码更加清晰。
-
灵活性:可以根据环境或条件的变化动态选择不同的策略。
缺点:
-
客户端必须了解可用策略:客户端代码需要了解各种策略类的存在和它们之间的差异,以便能够正确地使用它们。
-
可能增加系统的复杂性:如果存在很多策略,系统可能会变得复杂,尤其是当这些策略之间的差异不大时。
-
可能增加对象数量:每个策略都需要一个或多个对象,这可能会增加系统的内存消耗。
-
策略选择的复杂性:在有多种策略可供选择的情况下,选择合适的策略可能会变得复杂,尤其是在策略之间存在细微差别时。
-
性能考虑:在某些情况下,策略模式可能会引入额外的性能开销,尤其是在策略对象的创建和销毁频繁时。
【Tips】设计模式虽好,可不要贪杯额!
【都看到这了,点点赞点点关注呗,爱你们】😚😚
💬
✨ 正在努力的小新~
💖 超级爱分享,分享各种有趣干货!
👩💻 提供:模拟面试 | 简历诊断 | 独家简历模板
🌈 感谢关注,关注了你就是我的超级粉丝啦!
🔒 以下内容仅对你可见~
作者:不正经小新,CSDN后端领域新星创作者 |阿里云专家博主
CSDN个人主页:不正经小新
🔎GZH:不正经小新
🎉欢迎关注🔎点赞👍收藏⭐️留言📝