设计模式实战:从硬编码到灵活扩展的单位转换器
前言
通过重构单位转换器案例,揭示如何运用设计模式打造高扩展性系统,告别if-else地狱!
原始版本
在初始实现中,单位转换逻辑都堆积在一个方法里,典型的"万能上帝类"模式:
public static UnitValue convert(UnitValue unitValue, String targetUnit) {
int value = unitValue.getValue();
String unit = unitValue.getUnit();
// 重量转换
if (unit.equals("斤")) {
if (targetUnit.equals("公斤")) {
return new UnitValue(value / 2, targetUnit);
}
}
if (unit.equals("公斤")) {
if (targetUnit.equals("斤")) {
return new UnitValue(value * 2, targetUnit);
}
}
// 长度转换
if (unit.equals("厘米")) {
if (targetUnit.equals("米")) {
return new UnitValue(value / 100, targetUnit);
}
}
if (unit.equals("米")) {
if (targetUnit.equals("厘米")) {
return new UnitValue(value * 100, targetUnit);
}
}
throw new IllegalArgumentException();
}
使用示例:
UnitValue result = convert(new UnitValue(1, "公斤"), "斤");
// 输出: 2斤
❌ 存在问题:
- 修改风险高:新增转换规则需修改核心方法
- 职责不单一:违反单一职责原则
- 可读性差:大量if-else嵌套
- 扩展困难:每加新单位需手动修改代码
第一次重构:应用策略模式
通过策略模式将每种转换规则封装成独立类:
// 策略接口
public interface UnitConverter {
UnitValue convert(UnitValue unitValue, String targetUnit);
}
// 具体策略:公斤转斤
public class GongJinToJinConverter implements UnitConverter {
@Override
public UnitValue convert(UnitValue unitValue, String targetUnit) {
if (unitValue.getUnit().equals("公斤") && targetUnit.equals("斤")) {
int targetValue = unitValue.getValue() * 2;
return new UnitValue(targetValue, targetUnit);
}
return null;
}
}
// 具体策略:斤转公斤
public class JinToGongJinConverter implements UnitConverter {
@Override
public UnitValue convert(UnitValue unitValue, String targetUnit) {
if (unitValue.getUnit().equals("斤") && targetUnit.equals("公斤")) {
int targetValue = unitValue.getValue() / 2;
return new UnitValue(targetValue, targetUnit);
}
return null;
}
}
✅ 优化点:
- 职责分离:每个转换器负责单一转换逻辑
- 开闭原则:新增转换器不影响现有代码
- 解耦合:转换逻辑与调度逻辑分离
第二次重构:引入组合模式
通过组合模式创建可动态管理的转换器集合:
public class ComposableUnitConverter implements UnitConverter, ConverterManager {
private List<UnitConverter> converters = new ArrayList<>();
public ComposableUnitConverter() {
addDefaultConverters(this);
}
// 添加默认转换器
public static void addDefaultConverters(ConverterManager converterManager) {
converterManager.addConverter(new GongJinToJinConverter());
converterManager.addConverter(new JinToGongJinConverter());
converterManager.addConverter(new LiMiToMiUnitConverter());
converterManager.addConverter(new MiToLiMiUnitConverter());
}
@Override
public UnitValue convert(UnitValue unitValue, String targetUnit) {
for (UnitConverter converter : converters) {
UnitValue result = converter.convert(unitValue, targetUnit);
if (result != null) return result;
}
throw new IllegalArgumentException("不支持的单位转换");
}
// 动态管理转换器
@Override
public void addConverter(UnitConverter converter) {
converters.add(converter);
}
@Override
public boolean removeConverter(UnitConverter converter) {
return converters.remove(converter);
}
}
✅ 架构优势:
- 灵活扩展:运行时动态增删转换器
- 统一接口:使用者无需关心内部实现
- 便捷维护:默认转换器集中管理
- 支持扩展:轻松添加新单位(如温度、货币)
使用示例:
UnitConverter converter = new ComposableUnitConverter();
UnitValue result = converter.convert(new UnitValue(1, "公斤"), "斤");
// 输出: 2斤
假设需要新增公里与英里的转换:
// 新增策略类
public class KmToMileConverter implements UnitConverter {
@Override
public UnitValue convert(UnitValue unitValue, String targetUnit) {
if ("公里".equals(unitValue.getUnit()) && "英里".equals(targetUnit)) {
return new UnitValue((int)(unitValue.getValue() * 0.6214), targetUnit);
}
return null;
}
}
使用示例:
// 动态扩展系统
ComposableUnitConverter converter = new ComposableUnitConverter();
converter.addConverter(new KmToMileConverter());
UnitValue result = converter.convert(new UnitValue(10, "公里"), "英里");
// 输出: 6英里
扩展成本:仅需新增一个策略类+一行注册代码,核心架构零修改!
关键设计模式解析
-
策略模式(核心)
- 每个转换器实现统一接口
- 算法可互相替换
- 符合开闭原则
-
组合模式
- 树形结构管理转换器
- 统一处理单个和组合对象
- 支持递归组合
-
工厂方法模式
addDefaultConverters()隐藏对象创建细节- 集中管理默认配置
最佳实践总结
- 识别变化点:将频繁变更的逻辑(单位转换规则)独立封装
- 面向接口编程:依赖抽象(UnitConverter)而非具体实现
- 组合优于继承:通过对象组合动态扩展功能
- 开闭原则:新增功能通过扩展而非修改实现
通过这个案例可见,恰当运用设计模式能将硬编码的脆弱系统蜕变为高度灵活的框架。关键在于识别变化方向,运用模式封装变化点,最终实现配置即扩展的优雅架构。
本文举例重点在于设计模式的说明,实际上,代码依然有很多优化空间,比如使用转换器缓存,设计基于原有单位转换器的反向转换等等。

浙公网安备 33010602011771号