Architecture 实体标识-使用字符串而不是类型

Architecture 实体标识-使用字符串而不是类型,architecture,domain-driven-design,software-design,Architecture,Domain Driven Design,Software Design,我看过许多DDD帖子和书籍,其中实体类是从某种形式的基类派生的,基类具有实体标识类型的通用参数: public interface IEntity<out TKey> { TKey Id { get; } } public interface IComplexEntity<out TKey, in TEntity> { TKey Id { get; } bool IsSameAs(TEntity entity); } //Object

我看过许多DDD帖子和书籍,其中实体类是从某种形式的基类派生的,基类具有实体标识类型的通用参数:

public interface IEntity<out TKey>  
{
    TKey Id { get; }
}

public interface IComplexEntity<out TKey, in TEntity>  
{
    TKey Id { get; }
    bool IsSameAs(TEntity entity);
}

//Object Definition
public class TaxPayer : IComplexEntity<string, User>
{
    ...
}
最近,我一直致力于通过事件总线将事件传递给外部侦听器。我面临的“问题”是,我需要一种通用的消息格式来发送事件信封:

public EventEnvelope
{
    long EventStoreSequence; // from the event store
    bool IsReplay; // if event store is replaying from position 0 of stream
    object EventBeingSent; // this is the actual event, i.e. class     AddressChanged { string Old; string New; DateTime On; }
    object IdentityOfSender; // this is the identity of the entity who raised the event
}
上面的
IdentityOfSender
是一个对象,但实际值将是
字符串
int
Guid
等,具体取决于对象的标识类型

我的问题是为什么不简单地使用字符串作为标识?毕竟,guid、integer、name、number都可以表示为字符串,并且它们可以很容易地作为通用格式的字符串进行比较-这不仅可以使EventEnvelope更容易地使用字符串作为通用格式,还可以使实体更容易处理,而不需要基类或特殊类型


总之,为什么人们不推荐使用字符串作为身份的通用格式(或者我没有见过),而讨论身份的基类和泛型类型?

实际上,使用类型几乎没有任何好处-在任何编程语言中都可以轻松使用字符串

但还有一个更微妙的优势。字符串意味着字符串,只是一个字符序列。你必须知道上下文,一些字符串实际上意味着其他的东西。这对您来说可能很清楚,但我们不是为自己编写代码,而是为未来的读者编写代码。向其他人表明这一点非常重要——日期就是日期,ID就是ID,等等


此外,如果需要的话,以后扩展/重构某些特定的ID类型会容易得多

因为跨文化字符集中的字符串比较不容易。可以与字符串进行比较的最接近的数据类型是GUID。但即使GUID也可以有不同的字符串表示形式

例:

这三个都有相同的GUID值,但字符串比较不同。数字以千位分隔符/小数点格式的差异而闻名

此外,我认为标识的自定义类是提供显式标识比较。示例:信用卡号的前六位有一个六位数的发卡机构识别号(IIN)。也就是说,使您能够在域驱动设计中实现更高的灵活性。是的,这种设计阻止您使用“一对所有”的数据类型

不过,您可以通过对象映射为外部总线使用编解码模型。这样可以避免中断DDD,同时在整个外部总线中提供相同的格式

除此之外,这是一个一般性的指导方针。软件工程中的每一条准则都有其利弊。使用你认为最合适、最了解的,但在整个设计中保持一致

public EventEnvelope
{
    long EventStoreSequence; // from the event store
    bool IsReplay; // if event store is replaying from position 0 of stream
    object EventBeingSent; // this is the actual event, i.e. class     AddressChanged { string Old; string New; DateTime On; }
    object IdentityOfSender; // this is the identity of the entity who raised the event
}
{FD49D6AE-019C-4118-B7D1-A4DA54E4474F},
fd49d6ae-019c-4118-b7d1-a4da54e4474f,
FD49D6AE019C4118B7D1A4DA54E4474F