策略模式
约 2200 字大约 7 分钟
2026-01-16
1. 整体架构概述
GrouStrategy是一个样品信息操作的策略接口,定义了样品信息的核心操作方法,包括删除、更新、保存和数据分发等功能。在shgl-core-grou模块中,通过实现该接口,为不同类型的检测项目(如混凝土、化学分析等)提供了统一的操作入口。
2. 核心设计模式分析
2.1 策略模式(Strategy Pattern)
核心实现:
- 策略接口:
GrouStrategy定义了样品信息操作的标准方法 - 策略实现:三个具体实现类
GrouHntksServiceImpl、GrouHzServiceImpl、GrouHunServiceImpl - 策略上下文:
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 典型调用流程
初始化阶段:
- Spring容器启动时,自动扫描并实例化所有实现了GrouStrategy接口的Bean
- 通过构造函数注入到GrouService的strategyMap中
运行时调用:
- 客户端调用GrouService的方法,如
saveBatch - GrouService根据传入的flag参数从strategyMap中获取对应的策略实现
- 调用策略实现的对应方法完成具体操作
- 客户端调用GrouService的方法,如
4. 设计模式的优势与应用场景
4.1 优势
- 代码解耦:策略模式将不同检测类型的实现分离,降低了代码耦合度
- 扩展性强:新增检测类型时,只需实现GrouStrategy接口,无需修改现有代码
- 灵活性高:通过策略模式和工厂模式的结合,实现了运行时动态选择策略
- 代码复用:通过模板方法模式和适配器模式,复用了通用代码,减少了重复开发
4.2 应用场景
- 多种算法/实现选择:当需要根据不同条件选择不同的实现时
- 统一接口不同实现:当需要为不同类型的对象提供统一操作接口时
- 运行时动态切换:当需要在运行时根据配置或参数动态切换实现时
5. 面试常见问题与解答
5.1 问题1:GrouStrategy使用了哪些设计模式?请详细说明。
答案: GrouStrategy主要使用了以下设计模式:
策略模式:GrouStrategy作为策略接口,定义了样品信息操作的标准方法,三个实现类作为具体策略,GrouService作为策略上下文管理策略的使用。
工厂模式:利用Spring的依赖注入机制,将所有GrouStrategy实现自动收集到Map中,实现了策略的动态工厂。
模板方法模式:所有实现类都继承自ServiceImpl,复用了通用的CRUD操作,同时保持了方法实现的一致性。
适配器模式:通过convert方法将通用的GrouDTO转换为特定的实体类,处理了不同数据源之间的差异。
5.2 问题2:策略模式在这个项目中的具体应用是什么?有什么优势?
答案: 策略模式在项目中的具体应用是:
- 策略接口:GrouStrategy定义了样品信息操作的标准方法
- 具体策略:三个实现类分别对应不同类型的检测项目
- 策略上下文:GrouService通过strategyMap管理和使用不同的策略
优势:
- 实现了样品信息操作的统一接口,便于客户端调用
- 分离了不同检测类型的实现,降低了代码耦合度
- 提高了系统的扩展性,新增检测类型时只需实现接口
- 简化了客户端代码,客户端无需关心具体实现细节
5.3 问题3:如何新增一种新的检测类型?需要修改哪些代码?
答案: 新增一种新的检测类型需要以下步骤:
- 创建实体类:创建对应的实体类,如
GrouNewType - 创建Mapper:创建对应的Mapper接口,如
GrouNewTypeMapper - 创建Service接口:创建对应的Service接口,如
GrouNewTypeService - 创建Service实现:创建对应的Service实现类,如
GrouNewTypeServiceImpl,实现GrouStrategy接口 - 配置Spring注解:在实现类上添加
@Service("newtype_grou")注解 - 实现方法:实现GrouStrategy接口的所有方法,特别是
flag()方法返回对应的表名
不需要修改的代码:
- GrouStrategy接口
- GrouService类
- 其他实现类
这种设计使得系统具有良好的扩展性,符合开闭原则。
6. 代码优化建议
异常处理优化:
- 在GrouService中,当从strategyMap获取策略时,应添加空指针检查,避免策略不存在时的异常
- 建议添加策略不存在时的默认处理逻辑
策略注册优化:
- 考虑使用枚举类统一管理所有策略的flag值,避免字符串硬编码
- 可以添加策略注册的验证机制,确保所有策略的flag值唯一
代码复用优化:
- 三个实现类的convert方法和temp方法有很多相似之处,可以考虑提取公共基类
- 可以使用泛型进一步简化代码结构
性能优化:
- 在saveBatch方法中,可以考虑使用批量操作的优化,如分批处理大量数据
- 对于频繁访问的策略,可以考虑使用缓存机制提高性能
7. 总结
GrouStrategy相关实现类通过巧妙运用策略模式、工厂模式、模板方法模式和适配器模式等多种设计模式,实现了样品信息操作的统一接口和灵活扩展。这种设计不仅提高了代码的可维护性和可扩展性,也为系统的后续发展奠定了良好的基础。
在面试时,通过讲解这些设计模式的应用,可以展示对面向对象设计原则的理解和实际项目经验,是一个很好的技术亮点。
