如何为两个同实现的DDD值对象结构体复用代码?
解决方案建议
更优方案:提取通用逻辑到静态工具类
既然两个结构体的核心逻辑(IEquatable<T>、IComparable<T>实现、运算符重载、序列化)完全一致,仅类型标识不同,可将通用逻辑提取到静态工具类中复用,既保留独立类型的语义,又避免重复代码:
- 定义封装通用操作的静态工具类:
public static class VersionValueObjectHelper { public static bool Equals<T>(T left, object? right) where T : struct, IEquatable<T> { return right is T other && left.Equals(other); } public static int Compare<T>(T left, T right, Func<T, int> getValue) { return getValue(left).CompareTo(getValue(right)); } public static bool AreEqual<T>(T left, T right, Func<T, int> getValue) { return getValue(left) == getValue(right); } public static int ToInt<T>(T value, Func<T, int> getValue) { return getValue(value); } public static bool TryParse<T>(int input, Func<int, T> factory, out T result) { result = factory(input); return true; } }
- 两个结构体各自实现接口,调用工具类方法:
public readonly struct DefinitionVersion : IEquatable<DefinitionVersion>, IComparable<DefinitionVersion> { public int Value { get; } public DefinitionVersion(int value) => Value = value; public bool Equals(DefinitionVersion other) { return VersionValueObjectHelper.AreEqual(this, other, v => v.Value); } public override bool Equals(object? obj) { return VersionValueObjectHelper.Equals(this, obj); } public override int GetHashCode() => Value.GetHashCode(); public int CompareTo(DefinitionVersion other) { return VersionValueObjectHelper.Compare(this, other, v => v.Value); } public static bool operator ==(DefinitionVersion left, DefinitionVersion right) { return VersionValueObjectHelper.AreEqual(left, right, v => v.Value); } public static bool operator !=(DefinitionVersion left, DefinitionVersion right) { return !VersionValueObjectHelper.AreEqual(left, right, v => v.Value); } public static bool operator <(DefinitionVersion left, DefinitionVersion right) { return VersionValueObjectHelper.Compare(left, right, v => v.Value) < 0; } public static bool operator >(DefinitionVersion left, DefinitionVersion right) { return VersionValueObjectHelper.Compare(left, right, v => v.Value) > 0; } public static implicit operator int(DefinitionVersion version) => version.Value; public static explicit operator DefinitionVersion(int value) => new DefinitionVersion(value); } // InstanceVersion结构体仅替换类型名,逻辑完全复用工具类 public readonly struct InstanceVersion : IEquatable<InstanceVersion>, IComparable<InstanceVersion> { public int Value { get; } public InstanceVersion(int value) => Value = value; public bool Equals(InstanceVersion other) { return VersionValueObjectHelper.AreEqual(this, other, v => v.Value); } public override bool Equals(object? obj) { return VersionValueObjectHelper.Equals(this, obj); } public override int GetHashCode() => Value.GetHashCode(); public int CompareTo(InstanceVersion other) { return VersionValueObjectHelper.Compare(this, other, v => v.Value); } public static bool operator ==(InstanceVersion left, InstanceVersion right) { return VersionValueObjectHelper.AreEqual(left, right, v => v.Value); } public static bool operator !=(InstanceVersion left, InstanceVersion right) { return !VersionValueObjectHelper.AreEqual(left, right, v => v.Value); } public static bool operator <(InstanceVersion left, InstanceVersion right) { return VersionValueObjectHelper.Compare(left, right, v => v.Value) < 0; } public static bool operator >(InstanceVersion left, InstanceVersion right) { return VersionValueObjectHelper.Compare(left, right, v => v.Value) > 0; } public static implicit operator int(InstanceVersion version) => version.Value; public static explicit operator InstanceVersion(int value) => new InstanceVersion(value); }
这种方案的优势:
- 通用逻辑仅维护一份,避免后续修改遗漏
- 保留两个结构体的独立类型语义,符合DDD值对象的设计要求
- 可读性强,无泛型抽象门槛,也无需复杂代码生成
现有三种方案的选择建议
如果不想新增工具类,可根据场景选择:
- 复制粘贴:适合两个结构体后续几乎无修改的场景,实现最快,但需注意后续修改要同步更新两份代码,建议加注释提醒。
- 代码生成:仅当未来要新增大量类似Version类型时考虑,否则会额外增加模板、脚本的维护成本,属于过度设计。
- 泛型结构体:比如用
Version<TMarker>加标记类型区分,会增加语义理解门槛,其他开发者需要额外理解标记类型的作用,DDD场景下的类型直观性会下降。
综上,提取通用逻辑到静态工具类是最优选择;若场景简单,复制粘贴也可接受。
内容的提问来源于stack exchange,提问作者krimog
相关产品推荐
相关产品推荐

