领域驱动设计标识和价值对象

Domain Driven Design Identities and Value Objects

在 Vaughn Vernon Implementing Domain-driven Design 这本书和 code 中,他混合使用 IdentityValueObject 作为标识符。

public interface IIdentity
{
    string Id { get; }
}

public abstract class Identity : IEquatable<Identity>, IIdentity
{
    protected Identity() => this.Id = Guid.NewGuid().ToString();
    protected Identity(string id) => this.Id = id;
    // Currently for Entity Framework, set must be protected, not private. will be fixed in EF 6.
    public string Id { get; protected set; }

    public bool Equals(Identity id)
    {
        if (object.ReferenceEquals(this, id)) return true;
        if (object.ReferenceEquals(null, id)) return false;
        return this.Id.Equals(id.Id);
    }

    public override bool Equals(object anotherObject) => Equals(anotherObject as Identity);
    public override int GetHashCode() => (this.GetType().GetHashCode() * 907) + this.Id.GetHashCode();
    public override string ToString() => this.GetType().Name + " [Id=" + Id + "]";
}

和值对象:

public abstract class ValueObject
{
    // Returns all components of a value objects which constitute its identity.
    protected abstract IEnumerable<object> GetEqualityComponents();

    public override bool Equals(object obj)
    {
        if (object.ReferenceEquals(this, obj)) return true;
        if (object.ReferenceEquals(null, obj)) return false;
        if (this.GetType() != obj.GetType()) return false;
        var vo = obj as ValueObject;
        return GetEqualityComponents().SequenceEqual(vo.GetEqualityComponents());
    }

    public override int GetHashCode() => HashCodeHelper.CombineHashCodes(GetEqualityComponents());
}

我看到在某些情况下 ValueObject 被用作身份:

public class TaskId : ValueObject
{
    public TaskId()
        : this(Guid.NewGuid().ToString().ToUpper().Substring(0, 8))
    {
    }

    public TaskId(string id)
    {
        AssertionConcern.AssertArgumentNotEmpty(id, "The id must be provided.");
        AssertionConcern.AssertArgumentLength(id, 8, "The id must be 8 characters or less.");
        this.Id = id;
    }

    public string Id { get; private set; }

    protected override IEnumerable<object> GetEqualityComponents()
    {
        yield return this.Id;
    }
}

其他情况下它们是纯的Identity:

public class ForumId : SaaSOvation.Common.Domain.Model.Identity
{
    public ForumId(string id) : base(id) { }
}

对我来说,所有值都应该是 value object,包括 identities,所以我不明白这里有一个显式 Identity 的区别类型。

使用他的演示代码,how/why 他是否选择了上述方法来建模身份,是否有 advantage/disadvantage 优于其他方法?

两种实现都在比较属性的相等性,因此两者都遵循值对象的概念。 Identity class 专用于自定义身份类型的可重用值对象,它仍然具有相同的要求(使用任意字符串, 通常从 GUID/UUID) 创建。仍然是一个值对象,但是如果除了字符串 id 之外不需要其他属性,在这种情况下可以使用这个,同时仍然使用单独的派生 classes(如 ForumId)强类型化不同类型的身份。

另一方面,ValueObject class 正在处理需要在相应派生中进行比较的任意属性classes.

我认为从 ValueObject 而不是从 [=16] 派生 TaskId 的意图=]Identity 如果您查看构造函数,就会变得更加清晰。在这种情况下,特定的业务规则 - id 必须是八个字符或更少 - 需要在构造时完成,这对通用标识实现的定义。