实体身份 - 使用字符串而不是类型
Entity Identity - use of strings instead of type
我看过许多 DDD 帖子和书籍,其中实体 classes 是从某种形式的基础 class 派生的,该基础具有实体身份类型的通用参数:
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>
{
...
}
在 Vernon 的实施域驱动设计中,创建了特定类型以用作标识:
public class TaxPayerIdentity : Identity
{
public TaxPayerIdentity() { }
public TaxPayerIdentity(string id)
: base(id)
{
}
}
最近我一直致力于通过事件总线将事件传递给外部侦听器。 "issue" 我需要一个通用的消息格式来发送事件信封:
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
之上是一个对象,但实际值将是 string
、int
、Guid
等,具体取决于对象的身份类型。
我的问题是为什么不简单地使用字符串作为标识?毕竟,Guids、整数、名称、数字都可以表示为字符串,并且它们很容易与通用格式的字符串进行比较——这不仅会使 EventEnvelope 更容易使用字符串作为通用格式,还会使实体更容易无需基本 classes 或特殊类型即可处理?
所以综上所述,为什么人们不推荐使用字符串作为身份的通用格式(或者我没见过),而是谈论base classes和身份的通用类型?
实际上使用类型几乎没有任何好处 - 您可以在任何编程语言中轻松使用字符串。
但还有一个更微妙的优势。字符串表示字符串,只是一个字符序列。您必须知道某些字符串实际上意味着 其他内容 的上下文。您可能很清楚,但我们不是为自己编写代码,而是为未来的读者编写代码。向其他人说明这一点非常重要 - 日期是日期,ID 是 ID,等等。
此外,如果需要,以后扩展/重构某些特定 ID 类型会容易得多。
因为跨文化字符集中的字符串比较并不容易。可以与字符串进行比较的最接近的数据类型是 GUID。但即使是 GUID 也可以有不同的字符串表示形式。
例如:
{FD49D6AE-019C-4118-B7D1-A4DA54E4474F},
fd49d6ae-019c-4118-b7d1-a4da54e4474f,
FD49D6AE019C4118B7D1A4DA54E4474F
这三个都具有相同的 GUID 值但不同的字符串比较。数字以千位分隔符/小数点格式差异而闻名。
此外,我认为身份的自定义 class 是为了提供明确的身份比较。示例:信用卡号的前六位有一个六位发卡行识别号 (IIN) (wikipedia)。也就是说,使您在领域驱动设计中具有更高的灵活性。是的,该设计阻止您使用 "one for all" 数据类型。
不过,您可以通过对象映射为外部总线使用编码解码模型。这样你就可以避免破坏 DDD,同时在整个外部总线上提供相同的格式。
除此之外,这是一般准则。软件工程中的每条准则都有利有弊。使用您认为最合适和最了解的一个,但在整个设计中保持一致。
我看过许多 DDD 帖子和书籍,其中实体 classes 是从某种形式的基础 class 派生的,该基础具有实体身份类型的通用参数:
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>
{
...
}
在 Vernon 的实施域驱动设计中,创建了特定类型以用作标识:
public class TaxPayerIdentity : Identity
{
public TaxPayerIdentity() { }
public TaxPayerIdentity(string id)
: base(id)
{
}
}
最近我一直致力于通过事件总线将事件传递给外部侦听器。 "issue" 我需要一个通用的消息格式来发送事件信封:
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
之上是一个对象,但实际值将是 string
、int
、Guid
等,具体取决于对象的身份类型。
我的问题是为什么不简单地使用字符串作为标识?毕竟,Guids、整数、名称、数字都可以表示为字符串,并且它们很容易与通用格式的字符串进行比较——这不仅会使 EventEnvelope 更容易使用字符串作为通用格式,还会使实体更容易无需基本 classes 或特殊类型即可处理?
所以综上所述,为什么人们不推荐使用字符串作为身份的通用格式(或者我没见过),而是谈论base classes和身份的通用类型?
实际上使用类型几乎没有任何好处 - 您可以在任何编程语言中轻松使用字符串。
但还有一个更微妙的优势。字符串表示字符串,只是一个字符序列。您必须知道某些字符串实际上意味着 其他内容 的上下文。您可能很清楚,但我们不是为自己编写代码,而是为未来的读者编写代码。向其他人说明这一点非常重要 - 日期是日期,ID 是 ID,等等。
此外,如果需要,以后扩展/重构某些特定 ID 类型会容易得多。
因为跨文化字符集中的字符串比较并不容易。可以与字符串进行比较的最接近的数据类型是 GUID。但即使是 GUID 也可以有不同的字符串表示形式。
例如:
{FD49D6AE-019C-4118-B7D1-A4DA54E4474F},
fd49d6ae-019c-4118-b7d1-a4da54e4474f,
FD49D6AE019C4118B7D1A4DA54E4474F
这三个都具有相同的 GUID 值但不同的字符串比较。数字以千位分隔符/小数点格式差异而闻名。
此外,我认为身份的自定义 class 是为了提供明确的身份比较。示例:信用卡号的前六位有一个六位发卡行识别号 (IIN) (wikipedia)。也就是说,使您在领域驱动设计中具有更高的灵活性。是的,该设计阻止您使用 "one for all" 数据类型。
不过,您可以通过对象映射为外部总线使用编码解码模型。这样你就可以避免破坏 DDD,同时在整个外部总线上提供相同的格式。
除此之外,这是一般准则。软件工程中的每条准则都有利有弊。使用您认为最合适和最了解的一个,但在整个设计中保持一致。