问题是 - 实体可以由所有属性定义,或者仅由它的ID定义。
这是一个例子:
class Wallet{
int id;
Map<BillType, Bill> bills; //can have only 1 bill per bill type
void addBill(BillType billType, Bill bill){
this.bills.put(billType, bill);
}
}
//this is probably an Entity, since it is mutable, but it has no global Id (only local bound to wallet)
//and equality is based on all of the properties
class Bill{
BillType billType;
Map<TypeOfBillSide, SideOfBill> billSides; //can have only front or back
Bill(BillType billType){
this.billType = billType;
}
void drawWithPenOnBillSide(TypeOfBillSide typeOfBillSide, String drawing){
this.billSides.get(typeOfBillSide).drawWithPenOnBillSide(drawing);
}
void burn(){
System.out.println("I burned this bill");
}
}
//this is probably an Entity, since it is mutable, but it has no global Id (only local bound to Bill)
//and equality is based on all of the properties
class SideOfBill{
TypeOfBillSide typeOfBillSide;
String drawing;
public SideOfBill(TypeOfBillSide typeOfBillSide) {
this.typeOfBillSide = typeOfBillSide;
}
void drawWithPenOnBillSide(String drawing){
this.drawing = drawing;
System.out.println("I draw on this side " + this.drawing);
}
}
enum BillType{
DOLLAR_10,
DOLLAR_20,
DOLLAR_50;
}
enum TypeOfBillSide{
FRONT_SIDE,
BACK_SIDE
}
在这里,我有全球唯一的钱包 - 那是骨料根。它有账单,我认为在这种情况下是实体(因为我可以更改账单状态,而且钱包里仍然是该法案)。可以通过在账单的任何一侧绘制一些字符串来改变状态(在这种情况下,这也是实体)。
Bill本身只有作为钱包的一部分的意义,而且在钱包中,我只能有1种账单(我不能有2个账单,只有10美元,例如一个)。
如果我将其视为价值对象,并且使其成为不可变的对象,那么每次我在账单上绘制某些内容时,我都必须制作新的账单 - 在这种情况下,这有点奇怪,并且在代码中也很难做。<<<<<<<<<<<<
如果我将其视为全球唯一的实体,则必须拥有实际上是[Wallet.id&amp;Bill.Billtype]。但是在这种情况下
最自然的事情是,我将法案视为实体,并且具有测试所有账单属性的平等方法(与此同时,侧面的所有属性都包含在账单类中)。
这种常见的情况是否具有?
尽管不是常见的做法,但值botem(vo)肯定可能是突变的(例如,出于绩效原因)。但是,您需要确保无法共享可变的VO 。
仍然,对可变的vo的需求也许是一个有力的指标,即您要建模的概念实际上是一个实体。一个好问题要问自己是您是否对此实例的生命周期感兴趣。
例如,在您的情况下,保持账单上的变更历史的历史重要吗?如果是,则应将账单建模为实体。
如果我将其视为全球独特的实体,我将不得不 具有账单的ID,实际上是[Wallet.id&amp; Bill.Billtype]。但是在这种情况下
不要忘记,从域模型的角度来看,实体必须仅在其骨料根(AR)中唯一地识别。这意味着billType
可以用作钱包内的帐单ID。
还要注意,该账单可以从数据库的角度具有替代身份,或者(如果需要)(Walletid,cilltype)复合ID。注意:
-
重要的是要做出一个很好的决定,哪些对象是实体,哪个是vo。vo标识是由其内容(其代表的值)确定的。
从您所描述的情况下还不清楚。
通常,10 $是10 $,而Money
是所有书籍在谈论vo。
时显示的第一个示例但是,A Bill 可能是不同的,并且可能被视为实体。我可以有10美元的钞票,您可以拥有一张。它们的价值是相同的(在这个术语中是平等的),但是它们仍然是两个不同的实体,因此应该具有某些身份字段。但是,这可能不是您的情况。
如果您 do 认为账单是相同的,如果它们具有相同的billType
和drawing
,则是vo。 -
在解散的第二部分中,通常是不变的,从性质和定义上都是不变的。如果您有复杂的VO,则可以考虑使用著名的构建器图案。
一般想法是使用下一个规则:
1)DDD与概念/概念之间的业务和关系有关。实施并非严格定义。因此,最好编写详细的故事,然后展示您如何在域图上看到它。
2)一个实体是:
许多物体不是从根本上由其属性定义的,而是 而是通过连续性和身份的线程。(埃文斯)
例如,订单可以具有订单网络,价格,船舶和其他属性。如果有人更改ShiptingAddress,则订单保持相同的对象,而不是新订单。
。,即使您在系统中有两个订单,所有(订单网络,价格,船舶编号)仍然是不同的实体。唯一的区别是身份:ordernumber。
3)值对象由其所有属性定义。因此,这样做是不可变的,这很常见。
显而易见的例子是价格:
Price{
readonly Currency Currency;
readonly Decimal Amount;
}
value1 = new Price(Currency.USD, 1);
value2 = new Price(Currency.USD, 1);
Assert.IsTrue(value1 == value2);
不太明显的示例是总体中的vo的用法,这似乎适用于您的示例。
订单有订购,其中
OrderItem{
string ProductSKU;
int Amount;
}
将OrderItem
作为实体并添加OrderItemId
属性,例如,用于数据库编辑可能很方便。从业务角度来看,大多数时候根本不知道OrderItemId
。订购项目生活在其聚合根Order
内,并严格地将外部识别为一对{Order, OrderItem}
。在这种情况下,您甚至无法触摸OrderItem,而不必首先进入其汇总根。
现在,如果我们查看OrderItem,它是由其属性绝对识别的,那么它是值对象。
那么,"可以通过其所有属性来识别实体吗?" - 不,它是值对象的概念。