Skip to content

策略模式

约 2200 字大约 7 分钟

2026-01-16

1. 整体架构概述

GrouStrategy是一个样品信息操作的策略接口,定义了样品信息的核心操作方法,包括删除、更新、保存和数据分发等功能。在shgl-core-grou模块中,通过实现该接口,为不同类型的检测项目(如混凝土、化学分析等)提供了统一的操作入口。

2. 核心设计模式分析

2.1 策略模式(Strategy Pattern)

核心实现

  • 策略接口GrouStrategy 定义了样品信息操作的标准方法
  • 策略实现:三个具体实现类 GrouHntksServiceImplGrouHzServiceImplGrouHunServiceImpl
  • 策略上下文GrouService 作为策略的使用者,通过 strategyMap 管理不同的策略实现

代码示例

// 策略接口定义
public interface GrouStrategy {
    String flag();
    boolean removeBySampleId(Serializable id);
    // 其他方法...
}

// 策略实现
@Service("hntks_grou")
public class GrouHntksServiceImpl extends ServiceImpl<GrouHntksMapper, GrouHntks> implements GrouHntksService, GrouStrategy {
    @Override
    public String flag() {
        return "hntks_grou";
    }
    // 实现其他方法...
}

// 策略上下文
@Service
public class GrouService {
    private final Map<String, GrouStrategy> strategyMap = new ConcurrentHashMap<>();
    
    public GrouService(Map<String, GrouStrategy> strategyMap) {
        this.strategyMap.clear();
        strategyMap.forEach((k, v) -> {
            this.strategyMap.put(k, v);
        });
    }
    
    public boolean removeBySampleId(String flag, Serializable id) {
        flag = flag.toLowerCase();
        return this.strategyMap.get(flag).removeBySampleId(id);
    }
    // 其他方法...
}

设计意图

  • 实现了样品信息操作的统一接口,不同类型的检测项目可以有自己的实现
  • 客户端代码(GrouService)通过策略名称动态选择不同的实现
  • 提高了代码的可扩展性,新增检测项目类型时只需实现GrouStrategy接口

2.2 工厂模式(Factory Pattern)

核心实现

  • 利用Spring的依赖注入机制,将所有实现了GrouStrategy接口的Bean自动收集到Map中
  • GrouService通过构造函数接收这个Map,实现了策略的动态工厂

代码示例

// 构造函数接收所有GrouStrategy实现
public GrouService(Map<String, GrouStrategy> strategyMap) {
    this.strategyMap.clear();
    strategyMap.forEach((k, v) -> {
        this.strategyMap.put(k, v);
    });
}

设计意图

  • 利用Spring的IoC容器自动管理策略实现,无需手动创建
  • 实现了策略的动态注册和管理,提高了系统的灵活性
  • 简化了代码,减少了手动工厂类的编写

2.3 模板方法模式(Template Method Pattern)

核心实现

  • 三个实现类都继承自 ServiceImpl,复用了通用的CRUD操作
  • 每个实现类都遵循相似的方法实现模板,如 saveBatch 方法的实现结构

代码示例

@Override
public boolean saveBatch(List<GrouDTO> samples) {
    List<GrouHntks> list = new ArrayList<>();
    for (GrouDTO sample : samples) {
        GrouHntks bo = new GrouHntks();
        this.convert(bo, sample);
        list.add(bo);
    }
    return this.saveBatch(list);
}

设计意图

  • 通过继承 ServiceImpl 复用了通用的数据库操作方法
  • 统一了方法实现的结构,提高了代码的一致性
  • 子类可以通过重写 convert 方法实现特定的转换逻辑

2.4 适配器模式(Adapter Pattern)

核心实现

  • 每个实现类都通过 convert 方法将通用的 GrouDTO 转换为特定的实体类
  • 利用 BeanUtils.copyProperties 和 JSON 转换实现对象适配

代码示例

private void convert(GrouHntks bo, GrouDTO sample) {
    BeanUtils.copyProperties(sample, bo);
    String proprietaryData = sample.getProprietaryData();
    JSONObject json = JSONObject.parseObject(proprietaryData);
    GrouHntks object = json.toJavaObject(GrouHntks.class);
    this.temp(json, object);
    bo.merge(object);
    bo.setId(sample.getId());
}

设计意图

  • 实现了通用数据结构与特定实体类之间的转换
  • 处理了不同数据源之间的差异,如字段名称不一致的问题
  • 提高了系统的兼容性和可维护性

3. 代码结构与调用流程

3.1 组件关系图

┌─────────────────┐
  GrouStrategy   
  (策略接口)      
└─────────┬───────┘
          
          
┌─────────────────────────────────┐
           GrouService           
  (策略上下文,管理策略实现)       
└─────────┬───────────────────────┘
          
          
┌─────────┼─────────┐
                  
                  
┌─────────────────────────┐  ┌─────────────────────────┐  ┌─────────────────────────┐
 GrouHntksServiceImpl       GrouHzServiceImpl          GrouHunServiceImpl       
 (混凝土抗渗检测策略)        (化学分析检测策略)          (混凝土检测策略)          
└─────────────────────────┘  └─────────────────────────┘  └─────────────────────────┘

3.2 典型调用流程

  1. 初始化阶段

    • Spring容器启动时,自动扫描并实例化所有实现了GrouStrategy接口的Bean
    • 通过构造函数注入到GrouService的strategyMap中
  2. 运行时调用

    • 客户端调用GrouService的方法,如 saveBatch
    • GrouService根据传入的flag参数从strategyMap中获取对应的策略实现
    • 调用策略实现的对应方法完成具体操作

4. 设计模式的优势与应用场景

4.1 优势

  1. 代码解耦:策略模式将不同检测类型的实现分离,降低了代码耦合度
  2. 扩展性强:新增检测类型时,只需实现GrouStrategy接口,无需修改现有代码
  3. 灵活性高:通过策略模式和工厂模式的结合,实现了运行时动态选择策略
  4. 代码复用:通过模板方法模式和适配器模式,复用了通用代码,减少了重复开发

4.2 应用场景

  1. 多种算法/实现选择:当需要根据不同条件选择不同的实现时
  2. 统一接口不同实现:当需要为不同类型的对象提供统一操作接口时
  3. 运行时动态切换:当需要在运行时根据配置或参数动态切换实现时

5. 面试常见问题与解答

5.1 问题1:GrouStrategy使用了哪些设计模式?请详细说明。

答案: GrouStrategy主要使用了以下设计模式:

  1. 策略模式:GrouStrategy作为策略接口,定义了样品信息操作的标准方法,三个实现类作为具体策略,GrouService作为策略上下文管理策略的使用。

  2. 工厂模式:利用Spring的依赖注入机制,将所有GrouStrategy实现自动收集到Map中,实现了策略的动态工厂。

  3. 模板方法模式:所有实现类都继承自ServiceImpl,复用了通用的CRUD操作,同时保持了方法实现的一致性。

  4. 适配器模式:通过convert方法将通用的GrouDTO转换为特定的实体类,处理了不同数据源之间的差异。

5.2 问题2:策略模式在这个项目中的具体应用是什么?有什么优势?

答案: 策略模式在项目中的具体应用是:

  • 策略接口:GrouStrategy定义了样品信息操作的标准方法
  • 具体策略:三个实现类分别对应不同类型的检测项目
  • 策略上下文:GrouService通过strategyMap管理和使用不同的策略

优势

  • 实现了样品信息操作的统一接口,便于客户端调用
  • 分离了不同检测类型的实现,降低了代码耦合度
  • 提高了系统的扩展性,新增检测类型时只需实现接口
  • 简化了客户端代码,客户端无需关心具体实现细节

5.3 问题3:如何新增一种新的检测类型?需要修改哪些代码?

答案: 新增一种新的检测类型需要以下步骤:

  1. 创建实体类:创建对应的实体类,如 GrouNewType
  2. 创建Mapper:创建对应的Mapper接口,如 GrouNewTypeMapper
  3. 创建Service接口:创建对应的Service接口,如 GrouNewTypeService
  4. 创建Service实现:创建对应的Service实现类,如 GrouNewTypeServiceImpl,实现 GrouStrategy 接口
  5. 配置Spring注解:在实现类上添加 @Service("newtype_grou") 注解
  6. 实现方法:实现GrouStrategy接口的所有方法,特别是 flag() 方法返回对应的表名

不需要修改的代码

  • GrouStrategy接口
  • GrouService类
  • 其他实现类

这种设计使得系统具有良好的扩展性,符合开闭原则。

6. 代码优化建议

  1. 异常处理优化

    • 在GrouService中,当从strategyMap获取策略时,应添加空指针检查,避免策略不存在时的异常
    • 建议添加策略不存在时的默认处理逻辑
  2. 策略注册优化

    • 考虑使用枚举类统一管理所有策略的flag值,避免字符串硬编码
    • 可以添加策略注册的验证机制,确保所有策略的flag值唯一
  3. 代码复用优化

    • 三个实现类的convert方法和temp方法有很多相似之处,可以考虑提取公共基类
    • 可以使用泛型进一步简化代码结构
  4. 性能优化

    • 在saveBatch方法中,可以考虑使用批量操作的优化,如分批处理大量数据
    • 对于频繁访问的策略,可以考虑使用缓存机制提高性能

7. 总结

GrouStrategy相关实现类通过巧妙运用策略模式、工厂模式、模板方法模式和适配器模式等多种设计模式,实现了样品信息操作的统一接口和灵活扩展。这种设计不仅提高了代码的可维护性和可扩展性,也为系统的后续发展奠定了良好的基础。

在面试时,通过讲解这些设计模式的应用,可以展示对面向对象设计原则的理解和实际项目经验,是一个很好的技术亮点。