保定建设网站及推广连江建设局网站

张小明 2026/1/3 1:14:24
保定建设网站及推广,连江建设局网站,专业的营销型网站建设公司,保定建设信息网站作者#xff1a;打码养家 日期#xff1a;2025年12月19日 场景#xff1a;第三方登录系统重构#xff08;钉钉、企业微信等#xff09;一、背景#xff1a;为什么需要重构#xff1f;在开发一个 SaaS 平台时#xff0c;我们最初采用最朴素的方式实现第三方登录#xf…作者打码养家日期2025年12月19日场景第三方登录系统重构钉钉、企业微信等一、背景为什么需要重构在开发一个 SaaS 平台时我们最初采用最朴素的方式实现第三方登录// ❌ 初始版本硬编码 if-else 地狱 PostMapping(/login) public LoginInfoVo thirdPartyLogin(RequestParam String provider, RequestParam String code) { if (dingtalk.equals(provider)) { // 钉钉登录逻辑50行 return dingTalkService.login(code); } else if (wecom.equals(provider)) { // 企业微信登录逻辑60行 return weComService.login(code); } else if (feishu.equals(provider)) { // 飞书登录逻辑55行 return feishuService.login(code); } throw new IllegalArgumentException(不支持的登录方式: provider); } 问题暴露违反开闭原则每新增一个登录方式都要修改 Controller。职责混乱Controller 承担了“选择逻辑”和“业务调用”双重职责。难以测试无法单独测试某一种登录策略。耦合严重Controller 直接依赖所有 Service。二、第一次尝试仅使用策略模式我首先想到用策略模式解耦// ✅ 策略接口 public interface ThirdPartyLoginStrategy { LoginInfoVo login(String code); String getProvider(); } // ✅ 具体策略 Component public class DingTalkLoginStrategy implements ThirdPartyLoginStrategy { private final DingTalkService dingTalkService; // Spring Bean public DingTalkLoginStrategy(DingTalkService service) { this.dingTalkService service; } Override public LoginInfoVo login(String code) { return dingTalkService.login(code); } Override public String getProvider() { return dingtalk; } }❓ 我的第一个疑问客户端怎么用如果不用工厂客户端只能这样写// ❌ 客户端仍需硬编码 if (dingtalk.equals(provider)) { strategy new DingTalkLoginStrategy(dingTalkService); // ← 但 dingTalkService 是 Spring Bean }问题来了new DingTalkLoginStrategy(...)会导致dingTalkService为 null因为 Spring 无法管理手动new出来的对象。结论纯策略模式在 Spring 环境中无法直接使用除非策略不依赖任何 Bean。例子如果只用策略模式不用工厂也是完全可行的而且在某些简单场景下非常合适。但它的适用范围和优缺点与“策略工厂”组合有明显区别。✅ 一、什么是“纯策略模式”策略模式的核心思想是将一组算法/行为封装成独立的类它们实现同一个接口客户端可以在运行时选择使用哪一个。关键点客户端自己决定用哪个策略而不是通过工厂动态获取。 二、纯策略模式示例1. 策略接口public interface DiscountStrategy { BigDecimal applyDiscount(BigDecimal amount); }2. 具体策略public class VIPDiscountStrategy implements DiscountStrategy { public BigDecimal applyDiscount(BigDecimal amount) { return amount.multiply(BigDecimal.valueOf(0.8)); // 打8折 } } public class SeasonalDiscountStrategy implements DiscountStrategy { public BigDecimal applyDiscount(BigDecimal amount) { return amount.multiply(BigDecimal.valueOf(0.9)); // 打9折 } }3. 客户端直接使用无工厂public class OrderService { public BigDecimal calculatePrice(String userType, BigDecimal originalPrice) { DiscountStrategy strategy; if (VIP.equals(userType)) { strategy new VIPDiscountStrategy(); // ← 客户端自己 new } else { strategy new SeasonalDiscountStrategy(); // ← 客户端自己判断 } return strategy.applyDiscount(originalPrice); } }✅ 这就是纯策略模式没有工厂客户端直接创建并使用策略。✅ 三、什么时候适合只用策略模式场景说明策略数量少1~3个比如只有“普通用户”和“VIP”两种折扣选择逻辑简单固定if-else或switch足够清晰策略不需要 Spring Bean不依赖数据库、Redis、其他 Service性能敏感避免 Map 查找直接 new无额外开销一次性或脚本式代码不需要长期维护和扩展 例如工具类中的格式化策略、简单的配置开关等。三、引入工厂模式真正的解耦于是我决定引入工厂模式让 Spring 来管理策略的创建和注入。✅ 最终方案策略 工厂 Spring 自动注册1. 策略接口不变public interface ThirdPartyLoginStrategy { LoginInfoVo login(String code); String getProvider(); // 返回唯一标识如 dingtalk }2. 具体策略由 Spring 管理Component public class DingTalkLoginStrategy implements ThirdPartyLoginStrategy { private final DingTalkService dingTalkService; public DingTalkLoginStrategy(DingTalkService service) { this.dingTalkService service; } Override public LoginInfoVo login(String code) { return dingTalkService.login(code); } Override public String getProvider() { return dingtalk; } }✅ 所有策略类都加Component成为 Spring Bean。3. 工厂类核心Component public class LoginStrategyFactory { private final MapString, ThirdPartyLoginStrategy strategyMap new ConcurrentHashMap(); // Spring 自动注入所有实现了 ThirdPartyLoginStrategy 的 Bean public LoginStrategyFactory(ThirdPartyLoginStrategy[] strategies) { for (ThirdPartyLoginStrategy strategy : strategies) { strategyMap.put(strategy.getProvider(), strategy); } } public ThirdPartyLoginStrategy getStrategy(String provider) { ThirdPartyLoginStrategy strategy strategyMap.get(provider); if (strategy null) { throw new IllegalArgumentException(不支持的登录方式: provider); } return strategy; } }4. 客户端ControllerRestController RequiredArgsConstructor public class ThirdPartyLoginController { private final LoginStrategyFactory strategyFactory; PostMapping(/login) public LoginInfoVo login(RequestParam String provider, RequestParam String code) { ThirdPartyLoginStrategy strategy strategyFactory.getStrategy(provider); return strategy.login(code); } }四、关键设计细节解析 1. 为什么用构造器注入ThirdPartyLoginStrategy[]Spring 有一个强大特性当注入一个接口数组时会自动收集容器中所有该接口的实现类 Bean。private final ThirdPartyLoginStrategy[] strategies;→ 启动时Spring 自动把DingTalkLoginStrategy、WeComLoginStrategy等全部注入进来。✅无需手动注册无需修改工厂代码 2. 为什么用ConcurrentHashMapController 可能被高并发调用strategyMap在初始化后只读但初始化过程需线程安全ConcurrentHashMap保证init()方法在多线程下安全 实际上由于PostConstruct只在 Bean 初始化时调用一次普通HashMap也够用。但用ConcurrentHashMap更严谨。 3. 为什么策略类必须是Component只有被 Spring 管理才能自动注入DingTalkService等依赖只有是 Spring Bean才能被ThirdPartyLoginStrategy[]自动收集⚠️ 如果忘记加Component启动时strategies数组为空五、我的深度疑问与解答❓ 疑问 1这算“简单工厂”还是“工厂方法”这是“简单工厂”Simple Factory因为一个工厂类LoginStrategyFactory通过参数provider返回不同产品不是“工厂方法”Factory Method后者需要子类重写创建方法。✅ 在大多数业务场景中“简单工厂 策略”已足够。❓ 疑问 2能否不用工厂直接用ApplicationContext获取可以但不推荐// 不推荐 ThirdPartyLoginStrategy strategy applicationContext.getBean(provider LoginStrategy, ThirdPartyLoginStrategy.class);问题需要约定 Bean 名称脆弱无法统一校验“是否支持”引入全局状态难以测试✅ 工厂提供了抽象层隐藏了获取细节。❓ 疑问 3如果策略需要动态配置如 API 密钥怎么办可以在策略中注入配置Component public class DingTalkLoginStrategy implements ThirdPartyLoginStrategy { private final String appId; private final String appSecret; public DingTalkLoginStrategy(Value(${dingtalk.app-id}) String appId, Value(${dingtalk.app-secret}) String appSecret) { this.appId appId; this.appSecret appSecret; } }或者通过配置中心动态加载——不影响工厂策略结构。❓ 疑问 4如何支持“默认策略”或“组合策略”默认策略在getStrategy中加 fallbackif (strategy null) return defaultStrategy;组合策略如先钉钉再微信新增一个CompositeLoginStrategy实现✅ 策略模式天然支持扩展。六、优势总结为什么这个组合如此强大维度优化前优化后扩展性新增登录方式需改 Controller只需新增一个Component策略类可测试性无法单独测试钉钉逻辑可直接new DingTalkLoginStrategy(mock)可维护性登录逻辑散落在 Controller每个策略独立、职责单一健壮性魔法字符串dingtalk通过getProvider()统一管理Spring 集成手动调用 Service完全依赖注入符合 Spring 哲学七、适用场景扩展这套模式不仅适用于登录还可用于场景策略标识策略行为支付网关alipay,wechatpay(order)消息推送sms,email,wechatsend(message)文件解析excel,csv,jsonparse(file)权限校验role,acl,rbaccheck(user, resource)凡是“根据类型执行不同算法”的地方都适用此模式。八、避坑指南常见错误❌ 错误 1策略类忘记加Component→ 启动时不报错但运行时找不到策略。✅ 解决确保所有策略类被 Spring 扫描到。❌ 错误 2getProvider()返回值重复→ 后注册的策略会覆盖先注册的。✅ 解决使用枚举或常量避免手写字符串。❌ 错误 3在策略中做太多事→ 策略应只负责“协调”具体逻辑下沉到 Service。✅ 解决策略类保持轻量只调用其他 Service。九、未来演进方向策略元数据化用注解定义策略标识StrategyProvider(dingtalk) public class DingTalkLoginStrategy { ... }动态注册/卸载策略通过管理后台启用/禁用某些登录方式。策略性能监控在工厂中加入 Metrics 统计各策略调用次数、耗时。十、结语从最初的if-else到现在的策略 工厂 Spring 自动装配我深刻体会到好的设计不是一蹴而就的而是在解决实际问题中逐步演进的。这套模式不仅解决了当前需求更为未来扩展铺平了道路。它体现了面向对象的核心思想封装变化、依赖抽象、开闭原则。如果你也在处理类似的多实现场景不妨试试这个组合——它可能比你想象的更强大。附完整代码结构src/ └── main/ └── java/ └── com/rihuayun/auth/ ├── strategy/ │ ├── ThirdPartyLoginStrategy.java // 策略接口 │ ├── DingTalkLoginStrategy.java // 具体策略 │ └── WeComLoginStrategy.java ├── factory/ │ └── LoginStrategyFactory.java // 工厂类 └── controller/ └── ThirdPartyLoginController.java // 客户端
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

wordpress网站速度优化中国网站开发

NetworkX 库介绍与使用指南 NetworkX 是 Python 中用于创建、操作和分析复杂网络(图结构) 的核心库,支持无向图、有向图、加权图、多重图等多种图类型,内置丰富的图算法(路径分析、连通性、中心性、社区检测等&#xf…

张小明 2025/12/31 13:43:11 网站建设

石家庄营销网站建设怎样推广自己

万物互联时代,操作系统的分布式革新与开发框架的跨平台升级形成了技术共振。华为鸿蒙(HarmonyOS)以“设备协同”重构全场景体验底座,谷歌Flutter以“一致体验”破解多端开发痛点,二者的深度融合正成为全场景应用开发的…

张小明 2025/12/28 8:15:06 网站建设

国外建筑设计网站推荐嘉定网站设计制作优化排名

一份文档,三分靠写,七分靠改。而真正的“笔杆子”,连那三分的写作时间,也正在被AI重新定义。 深夜,小王对着屏幕上那篇语法挑不出毛病、结构四平八稳、但读起来就是“没内味儿”的策划案,发出了第N次叹息。…

张小明 2025/12/31 16:00:09 网站建设

青岛网站建设哪个好电话用网站做综合布线

你是否正在寻找一个能够快速搭建企业级后台管理系统的解决方案?🤔 Admin.NET基于.NET 6/8和Vue3技术栈,为你提供了一套完整的权限管理开发框架。无论你是要开发OA系统、企业资源规划系统还是电商后台,这个框架都能帮你节省大量开发…

张小明 2026/1/2 17:03:38 网站建设

专门写文章的网站班级网站建设方案

2、系统总体设计 2.1硬件的总体设计 为了使门禁系统智能化,需要一个主控芯片对整个门禁系统进行管理控制。接着还需要对应的模块完成包括数字密码验证和IC卡识别验证的功能。当出现非法闯入、验证失败等情况时还需要对操作人员进行警告。最后需要一个人机交互界面方…

张小明 2025/12/28 8:14:59 网站建设

工程建设科学技术奖申报网站深圳小程序开发公司

这项由小米公司HyperAI团队开展的研究发表于2024年12月,论文编号为arXiv:2512.14052v1。有兴趣深入了解的读者可以通过该编号查询完整论文内容。当我们拿起手机拍照、截图或者浏览图片时,是否曾经希望手机能像人类一样"看懂"这些画面&#xff…

张小明 2025/12/28 8:14:57 网站建设