You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Dart中枚举能否共享具体方法以避免代码重复?

优化单位转换枚举的重复逻辑方案

问题背景

我使用带有枚举类型unit属性的值对象,这些枚举实现接口以支持单位转换(如厘米转米、千克转克等)。示例代码如下:

class Height {
  final double value;
  final DistanceUnit unit;
  
  const Height({required this.value, this.unit = DistanceUnit.cm});
}
// 限制仅枚举能实现此接口,这对其他方法很重要
abstract interface class Convertible implements Enum {
  final double factor;

  Convertible({required this.factor});

  double getConversionFactor(covariant Convertible from, covariant Convertible to);
}

enum DistanceUnit implements Convertible {
  cm(factor: 1/100),
  m(factor: 1);
  
  @override
  final double factor;
  
  const DistanceUnit({required this.factor});
  
  @override
  double getConversionFactor(covariant Convertible from, covariant Convertible to) {
    return from.factor / to.factor;
  }
}

当前代码运行正常,但由于存在面积、距离、体积、时间、质量等多种单位,getConversionFactor()方法需重复编写,违反了DRY原则。已知枚举继承自Enum且无法扩展其他类,需要优化方案。


优化方案

方案1:给Convertible接口添加默认方法

Dart 2.17及以上版本支持抽象接口类定义默认方法,我们可以把getConversionFactor的通用逻辑直接内嵌到接口中,所有实现Convertible的枚举会自动继承这个方法,无需重复编写。

修改后的Convertible接口:

abstract interface class Convertible implements Enum {
  final double factor;

  Convertible({required this.factor});

  // 通用转换逻辑作为默认方法实现
  double getConversionFactor(covariant Convertible from, covariant Convertible to) {
    return from.factor / to.factor;
  }
}

后续新增单位枚举时,只需要实现Convertible并定义factor即可:

enum MassUnit implements Convertible {
  g(factor: 1/1000),
  kg(factor: 1);

  @override
  final double factor;

  const MassUnit({required this.factor});
  // 无需重写getConversionFactor,直接使用接口默认实现
}

方案2:用扩展方法提取通用逻辑

如果不想修改原有接口结构,可以通过扩展方法把转换逻辑抽离出来,作用于所有实现Convertible的枚举:

// 定义扩展方法
extension ConvertibleExtension on Convertible {
  double getConversionFactor(covariant Convertible from, covariant Convertible to) {
    return from.factor / to.factor;
  }
}

此时Convertible接口可以移除getConversionFactor的声明:

abstract interface class Convertible implements Enum {
  final double factor;

  Convertible({required this.factor});
}

调用时直接通过扩展方法使用:

// 示例:厘米转米
final cm = DistanceUnit.cm;
final m = DistanceUnit.m;
print(cm.getConversionFactor(cm, m)); // 输出0.01

方案对比

  • 方案1更贴合接口设计的职责内聚原则,代码结构更直观,推荐优先使用。
  • 方案2属于无侵入式扩展,适合无法修改原有接口的场景。

两种方案都能彻底消除重复代码,符合DRY原则,完美适配Dart枚举不能继承类的限制。

内容的提问来源于stack exchange,提问作者Galactose

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 22:17:41