我刚开始阅读DDD.我无法完全掌握Entity vs Value对象的概念.有人可以解释当Value对象被设计为Entity对象时系统可能遇到的问题(可维护性,性能等等)吗?例子很棒......
最近遇到了不可变对象的概念,我想知道控制状态访问的最佳实践.即使我的大脑的面向对象部分让我想要在公众成员的视线中畏缩,但我认为没有类似这样的技术问题:
public class Foo {
public final int x;
public final int y;
public Foo( int x, int y) {
this.x = x;
this.y = y;
}
}
Run Code Online (Sandbox Code Playgroud)
我觉得更适合声明字段private并为每个字段提供getter方法,但是当状态明确只读时,这似乎过于复杂.
提供对不可变对象状态的访问的最佳实践是什么?
我还没有看到任何示例,但我认为它们保存在数据库中的包含实体表中.
IE浏览器.如果我有一个Person实体/聚合根和一个相应的Person表,如果它有一个名为Address的值对象,则Address值将保存在此Person表中!
对于我有其他实体(如公司等)拥有地址的域名,这是否有意义?
(我目前正在编写项目管理应用程序并尝试进入DDD)
(这个问题使用PHP作为上下文,但不仅限于PHP.例如,任何内置哈希的语言也是相关的)
我们来看看这个例子(PHP):
function makeAFredUsingAssoc()
{
return array(
'id'=>1337,
'height'=>137,
'name'=>"Green Fred");
}
Run Code Online (Sandbox Code Playgroud)
与:
class Fred
{
public $id;
public $height;
public $name;
public function __construct($id, $height, $name)
{
$this->id = $id;
$this->height = $height;
$this->name = $name;
}
}
function makeAFredUsingValueObject()
{
return new Fred(1337, 137, "Green Fred");
}
Run Code Online (Sandbox Code Playgroud)
方法#1当然更简洁,但它可能很容易导致错误,例如
$myFred = makeAFredUsingAssoc();
return $myFred['naem']; // notice teh typo here
Run Code Online (Sandbox Code Playgroud)
当然,有人可能会争辩说$myFred->naem同样会导致错误,这是事实.然而,正式课程对我来说感觉更加僵硬,但我无法证明这一点.
使用每种方法的优点/缺点是什么?人们何时应该使用哪种方法?
假设我们拥有受CQRS启发的架构,其中包括命令,域模型,域事件,读取模型DTO等组件.
当然,我们可以在域模型中使用值对象.我的问题是,它们是否也应用于:
我没有看到任何在上述组件中使用Value Objects(VO)的示例.相反,使用原始类型.也许这只是简单的例子.毕竟,我对DDD中使用VO的理解是它们可以作为整个应用程序的粘合剂.
我的动机:
命令.
假设用户提交包含地址字段的表单.我们有Address Value Object来表示这个概念.在客户端构造命令时,我们应该验证用户输入,当它格式正确时,我们可以在那里创建Address对象并用它初始化Command.我认为不需要将Address对象的创建委托给命令处理程序.
域事件.
域模型已经在值对象方面运行,因此通过使用VO发布事件而不是将它们转换为基本类型,我们可以避免使用某些映射代码.我很确定在这种情况下使用VO是可以的.
DTO的.
如果我们的查询端DTO可以包含值对象,则可以提供更多灵活性.例如,如果我们有Money对象,我们可以选择是以EUR还是USD显示,不需要更改Read Model.
我不明白为什么DDD中的值对象应该是不可变的,我也不知道如何轻松完成.(如果重要的话,我专注于C#和实体框架.)
例如,让我们考虑经典的Address值对象.如果你需要改变"解放路123号"到"123主街 ",我为什么要需要构建一个全新的对象,而不是说myCustomer.Address.AddressLine1 ="123大街"的?(即使实体框架支持结构,这仍然是一个问题,不是吗?)
我理解(我认为)价值对象没有身份并且是域对象的一部分的想法,但有人可以解释为什么不变性是一件好事吗?
编辑:我在这里的最后一个问题应该是"有人可以解释为什么不变性是适用于价值对象的好东西吗?" 对困惑感到抱歉!
编辑:为了clairfy,我不是在询问CLR值类型(与引用类型相比).我问的是价值对象的更高级DDD概念.
例如,这里是实现不可变的值类型实体框架劈上下的方式: http://rogeralsing.com/2009/05/21/entity-framework-4-immutable-value-objects.基本上,他只是让所有的安装者都私密.为什么要经历这样做的麻烦?
是否可以在教义实体中嵌入的值对象上使用继承?
我正在考虑的情况是:
我有一个拥有和嵌入值对象的实体.该值对象具有以下层次结构:
class myEntity {
/** @Embedded(class = "baseValueObject") */
private $value_object;
...
}
class baseValueObject {...}
class valueObject1 extends baseValueObject{...}
class valueObject2 extends baseValueObject2{...}
Run Code Online (Sandbox Code Playgroud)
如果我将我的实体定义为可嵌入的baseValueObject,那么当我使用模式工具更新我的数据库模式时没有任何反应,所以我想这不是这样做的方法.
我正在考虑的另一个选择是在实体上使用单表继承来创建使用其中一个值对象的子实体,并为另一个创建另一个子实体.像这样:
class myEntity {
/** @Embedded(class = "baseValueObject") */
private $value_object;
...
}
class myEntityA extends myEntity {
/** @Embedded(class = "valueObject1") */
private $value_object;
...
}
class myEntityB extends myEntity {
/** @Embedded(class = "valueObject2") */
private $value_object;
...
}
class baseValueObject {...}
class valueObject1 extends baseValueObject{...}
class valueObject2 extends …Run Code Online (Sandbox Code Playgroud) 值对象没有标识.ORM需要标识来更新数据库.
如何欺骗ORM?
(将值对象标记为内部将不起作用,因为ORM位于不同的程序集中并将其移动到同一程序集是不可接受的).
提前致谢.
由于没有值对象的存储库.如何加载所有值对象?
假设我们正在为博客应用程序建模,我们有这些类:
我知道当我保存一篇新帖子时,它的标签会随同它一起保存在同一个表格中.但是我如何加载所有帖子的所有标签.PostsRespository应该有一个加载所有标签的方法吗? 我经常这样做,但我想知道别人的意见
当您从控制器内的UI接收字符串格式的参数时,是否直接将字符串传递给应用程序服务(或命令)?
或者,您是否从控制器内的字符串创建值对象?
new Command(new SomeId("id"), Weight.create("80 kg"), new Date())
Run Code Online (Sandbox Code Playgroud)
要么
new Command("id", "80 kg", new Date())
new Command("id", "80", "kg", new Date())
Run Code Online (Sandbox Code Playgroud)
也许这不重要,但它困扰我.
问题是,我们应该将域中的值对象耦合到控制器(内部)吗?
想象一下,在应用程序层和表示层之间没有Web(如android活动或swing),你会在UI中推动使用值对象吗?
另外,你是否将值对象序列化/反序列化为字符串?
Weight weight = Weight.create("80 kg");
weight.getValue().equals(80.0);
weight.getUnit().equals(Unit.KILOGRAMS);
weight.toString().equals("80 kg");
Run Code Online (Sandbox Code Playgroud)
在将字符串传递给命令的情况下,我宁愿传递"80 kg"而不是"80"和"kg".
对不起,如果问题不相关或有趣.
谢谢.
我在搜索有关完全不同的主题的信息时遇到了这个帖子:CQRS中的值对象 - 在哪里使用
他们似乎更喜欢基元或DTO,并将VO保留在域内.
我还看了V. Vernon(实施DDD)这本书,它在第14章(第522页)中谈到(确切地说是-_-)
我注意到他在没有任何DTO的情况下使用命令.
someCommand.setId("id");
someCommand.setWeightValue("80");
someCommand.setWeightUnit("kg");
someCommand.setOtherWeight("80 kg");
someCommand.setDate("17/03/2015 17:28:35");
someCommand.setUserName("...");
someCommand.setUserAttribute("...");
someCommand.setUserOtherAttributePartA("...");
someCommand.setUserOtherAttributePartB("...");
Run Code Online (Sandbox Code Playgroud)
它是由控制器映射的命令对象.值对象初始化将出现在命令处理程序方法中,并且它们会在值不正确的情况下抛出一些东西(初始化中的自我验证).
我想我开始不那么烦恼,但其他一些意见也会受到欢迎.
value-objects ×10
php ×2
cqrs ×1
doctrine ×1
dto ×1
entityobject ×1
identity ×1
immutability ×1
inheritance ×1
java ×1
oop ×1
repository ×1