1

在《实现 DDD》一书中,提到了创建TenantId值对象。这对我来说很有意义,因为 aGUID可能是空的,它不是有效的TenantId,所以通过创建一个TenantId值对象,我可以防止这种情况(我还有其他值对象,如Name, PhoneNumber,EmailAddress等):

public class TenantId
{
    public TenantId(Guid id)
    {
        this.SetId(id);
    }

    public Guid Id { get; private set; }

    private void SetId(Guid id)
    {
        if (id == Guid.Empty)
        {
            throw new InvalidOperationException("Id must not be an empty GUID.");
        }

        this.Id = id;
    }
}

我感兴趣的是,我应该还是不应该TenantId在服务方法上使用它,例如:

TenantId tenantId = new TenantId(model.TenantId); // model.TenantId being a GUID.

this.tenantService.GetTenant(tenantId);

或者我应该在服务方法参数中使用更原始的形式:

this.tenantService.GetTenant(model.TenantId); // again model.TenantId is a GUID.

这本书似乎有时以一种方式,有时另一种方式。人们对这些方法的优缺点有何看法?

4

2 回答 2

3

如果服务不需要对实体的受限访问,请传递值对象,因为它是一个共享标识符,但我会将其编码如下:

public class TenantId : IEquatable<TentantId>
{
    public TenantId(Guid id)
    {
        if (id == Guid.Empty)
        {
            throw new InvalidOperationException("TenantId must not be an empty GUID.");
        }
        _id = id;
    }

    private readonly Guid _id;

    public Equals(TentantId other)
    {
        if (null == other) return false;
        return _id.Equals(other._id);
    }

    public GetHashcode()
    {
        return _id.GetHashcode();
    }

    public override Equals(object other)
    {
        return Equals(other as TenantId);
    }

    public ToString()
    {
        return _id.ToString();
    }
}

然而在某些情况下,域服务应该只使用用户可以在存储库中访问的实体来调用:在这些情况下,域服务的公共接口需要实体(即使实现只使用标识符)。

于 2013-09-04T08:31:32.727 回答
1

我更喜欢使用自定义值对象作为聚合的标识。我认为当其他开发人员想要调用 api 时,它会提供更多线索。考虑一下:

Tenant findBy(String identity); //others may pass an String instance but not id and the compliler can't check it out for you

你不能在下面添加这个方法:

Tenant findBy(String name);//assuming name unique but it failed for compiling

如果您已经拥有特定类型,为什么还要使用原始类型?

编辑

我通常将自定义类型用于存储库和应用程序服务,对于域服务,请参考 @Giacomo Tesio 的答案。我认为“直接使用实体”更有意义。

于 2013-09-04T01:08:05.953 回答