工厂模式和策略模式的组合设计

背景
项目中因为涉及到多个保司的场景,把多个保司的业务处理逻辑一致的内容放到一起,特殊保司的处理逻辑单独拉出来。涉及这类的需求项目中常用到 工厂模式(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(标准操作流程 / 指导原则)

工厂 + 策略模式使用流程:

  1. 输入参数解析:
    • 从请求中获取 [insuranceMark](file://D:\workspace\autoshop\caris-platform\business\caris-auto-base\src\main\java\com\ebao\caris\common\vo\FileUploadVO.java#L10-L10)(保险公司标识)。
  2. 策略选择:
    • 调用 [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) 获取对应的策略实例。
  3. 策略执行:
    • 调用 handler.singlePolicyVerifyData(...) 执行具体的业务逻辑。
  4. 策略扩展:
    • 新增策略只需继承 [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() 方法中加入默认值判断。
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容