背景
项目中因为涉及到多个保司的场景,把多个保司的业务处理逻辑一致的内容放到一起,特殊保司的处理逻辑单独拉出来。涉及这类的需求项目中常用到 工厂模式(Factory Pattern) 和 策略模式(Strategy Pattern) 的组合设计。可以降低耦合,便于扩展维护。以保单验真为例分析下这种设计模式。
代码:
PolicyVerifyAbstractHandler handler = PolicyVerifyServiceFactory.getHandler(policyVerifyDto.getInsuranceMark());
handler.singlePolicyVerifyData(policyVerifyDto, queryCarisSinglePolicy(policyVerifyDto));
✅ Glossary(术语表)
| 术语 | 描述 |
|---|---|
工厂模式 |
Factory Pattern,通过一个工厂类统一创建不同类型的对象实例。 |
策略模式 |
Strategy Pattern,定义一系列算法或行为,并在运行时动态切换。 |
| [PolicyVerifyServiceFactory](file://D:\workspace\autoshop\caris-platform\business\caris-auto-api\src\main\java\com\ebao\insurance\grandauto\pa\service\handler\factory\PolicyVerifyServiceFactory.java#L8-L25) | 工厂类,用于根据 [insuranceMark](file://D:\workspace\autoshop\caris-platform\business\caris-auto-base\src\main\java\com\ebao\caris\common\vo\FileUploadVO.java#L10-L10) 返回对应的 [PolicyVerifyAbstractHandler](file://D:\workspace\autoshop\caris-platform\business\caris-auto-api\src\main\java\com\ebao\insurance\grandauto\pa\service\handler\PolicyVerifyAbstractHandler.java#L33-L283) 实例。 |
| [PolicyVerifyAbstractHandler](file://D:\workspace\autoshop\caris-platform\business\caris-auto-api\src\main\java\com\ebao\insurance\grandauto\pa\service\handler\PolicyVerifyAbstractHandler.java#L33-L283) | 抽象策略接口/基类,定义统一的处理方法 [singlePolicyVerifyData()](file://D:\workspace\autoshop\caris-platform\business\caris-auto-api\src\main\java\com\ebao\insurance\grandauto\pa\service\handler\PolicyVerifyAbstractHandler.java#L72-L78)。 |
| [PolicyVerifyDefaultHandler](file://D:\workspace\autoshop\caris-platform\business\caris-auto-api\src\main\java\com\ebao\insurance\grandauto\pa\service\handler\impl\PolicyVerifyDefaultHandler.java#L15-L60) | 策略实现类之一,提供默认保单验真逻辑。 |
| [PAICVerifyNameHandler](file://D:\workspace\autoshop\caris-platform\business\caris-auto-api\src\main\java\com\ebao\insurance\grandauto\pa\service\handler\impl\PAICVerifyNameHandler.java#L8-L124) | 特定保险公司(如 HQ_PAIC)的验真策略实现类。 |
📘 SOP / Guideline(标准操作流程 / 指导原则)
工厂 + 策略模式使用流程:
-
输入参数解析:
- 从请求中获取 [insuranceMark](file://D:\workspace\autoshop\caris-platform\business\caris-auto-base\src\main\java\com\ebao\caris\common\vo\FileUploadVO.java#L10-L10)(保险公司标识)。
-
策略选择:
- 调用 [PolicyVerifyServiceFactory.getHandler(insuranceMark)](file://D:\workspace\autoshop\caris-platform\business\caris-auto-api\src\main\java\com\ebao\insurance\grandauto\pa\service\handler\factory\PolicyVerifyServiceFactory.java#L12-L17) 获取对应的策略实例。
-
策略执行:
- 调用
handler.singlePolicyVerifyData(...)执行具体的业务逻辑。
- 调用
-
策略扩展:
- 新增策略只需继承 [PolicyVerifyAbstractHandler](file://D:\workspace\autoshop\caris-platform\business\caris-auto-api\src\main\java\com\ebao\insurance\grandauto\pa\service\handler\PolicyVerifyAbstractHandler.java#L33-L283) 并注册到工厂中即可,无需修改已有调用逻辑。
💡 Best Practice(最佳实践)
- 解耦策略与调用者:通过工厂返回具体策略实例,避免在业务逻辑中硬编码判断逻辑。
- 易于扩展:新增一种保险公司验真方式只需添加新的 Handler 类并注册进工厂。
- 统一接口规范:所有策略都实现统一抽象类的方法,便于管理和测试。
- 支持运行时切换:策略可在运行时根据业务条件动态决定,提升灵活性。
- 组件可插拔:策略类作为 Spring Bean 注册后自动注入工厂,符合 Spring IOC 思想。
🔍 Checklist / Validation Rule(检查清单 / 验证规则)
| 检查项 | 是否符合规范 |
|---|---|
| 是否为每个策略类定义统一接口? | ✅ |
| 工厂是否封装了策略实例的创建逻辑? | ✅ |
| 是否支持策略的动态注册和替换? | ✅ |
| 是否有默认策略兜底? | ✅ |
| 是否将策略类注册为 Spring Bean? | ✅ |
| 是否存在 if-else 判断策略类型? | ❌(应由工厂负责) |
📄 Sample(示例代码)
1. 抽象策略类
public abstract class PolicyVerifyAbstractHandler {
public abstract void singlePolicyVerifyData(PolicyVerifyUploadResultBO policyVerifyDto, ReportPolicyPO policy);
}
2. 具体策略类
@Component
public class PolicyVerifyDefaultHandler extends PolicyVerifyAbstractHandler {
@Override
public void singlePolicyVerifyData(PolicyVerifyUploadResultBO policyVerifyDto, ReportPolicyPO policy) {
// 默认逻辑
}
}
@Component
public class PAICVerifyNameHandler extends PolicyVerifyAbstractHandler {
@Override
public void singlePolicyVerifyData(PolicyVerifyUploadResultBO policyVerifyDto, ReportPolicyPO policy) {
// 特殊逻辑
}
}
3. 工厂类
public class PolicyVerifyServiceFactory {
private static final Map<String, PolicyVerifyAbstractHandler> map = new HashMap<>();
public static PolicyVerifyAbstractHandler getHandler(String name) {
if (StringUtils.isEmpty(name) || !map.containsKey(name)) {
name = "Default";
}
return map.get(name);
}
public static void setPolicyVerifyHandler(String name, PolicyVerifyAbstractHandler handler) {
if (StringUtils.isNotEmpty(name) && handler != null) {
map.put(name, handler);
}
}
}
4. 初始化策略类(Spring 注入)
@Override
public void afterPropertiesSet() {
PolicyVerifyServiceFactory.setPolicyVerifyHandler("Default", this);
}
🧾 Template(模板结构)
// 抽象策略类
public abstract class AbstractHandler {
public abstract void execute();
}
// 具体策略类A
public class HandlerA extends AbstractHandler {
public void execute() { /* 实现逻辑 */ }
}
// 具体策略类B
public class HandlerB extends AbstractHandler {
public void execute() { /* 实现逻辑 */ }
}
// 工厂类
public class HandlerFactory {
private static Map<String, AbstractHandler> handlers = new HashMap<>();
public static AbstractHandler getHandler(String type) {
return handlers.getOrDefault(type, handlers.get("default"));
}
public static void registerHandler(String type, AbstractHandler handler) {
handlers.put(type, handler);
}
}
🧠 Lesson Learned(经验总结)
✅ 正面经验
- 使用策略+工厂模式有效减少冗余判断逻辑,提高代码可维护性。
- 将不同保险公司的验真逻辑分离为独立类,便于后期维护和扩展。
- 结合 Spring IOC 容器管理策略类生命周期,降低耦合度。
- 提供默认策略兜底,增强系统健壮性。
❌ 负面经验
- 如果不及时清理未使用的策略类,可能导致内存浪费或误加载。
- 忘记在
afterPropertiesSet()中注册策略,会导致策略不可用。 - 若工厂类未做容错处理,传入无效 key 可能导致 NPE。
⚠️ Bad Experience(踩坑案例)
案例 1:策略未注册导致空指针异常
-
现象:调用
handler.singlePolicyVerifyData(...)报 NPE。 -
原因:忘记在
afterPropertiesSet()中注册策略类到工厂。 -
修复:确保每个策略类在初始化时调用
setPolicyVerifyHandler(...)注册自己。
案例 2:策略类重复注册覆盖原有实例
- 现象:多个策略类注册为同一个 key,导致实际执行逻辑不一致。
- 原因:策略 key 冲突,后者覆盖前者。
- 修复:保证策略 key 唯一性,或增加日志提醒冲突情况。
案例 3:策略配置错误导致默认策略未生效
-
现象:传入未知
insuranceMark,但未走默认策略。 - 原因:工厂未设置默认兜底逻辑。
-
修复:在
getHandler()方法中加入默认值判断。