如何构建复杂的值对象?
How to build complex value-object?
我刚刚开始学习DDD。所以我为愚蠢的问题道歉...
所以我有了 Post
实体。看起来不错。但它应该有 tags
。
在代码中它看起来像这样(ruby 代码):
class Post
attr_reader :tags
attr_reader :title
attr_reader :text
# ...
end
class Tag
attr_reader :name
attr_reader :description
# ...
end
标签作为实体没有意义。我不需要 tag
本身。
但是我应该如何为 post 实现存储库?
我发现了 2 个变体:
1.
在同一个存储库中构建标签。像这样:
# PostRepository
def find(id)
# getting post data from storage here
# getting tags data
Post.new(title, text, tags_data.map { |tag_data| Tag.new(tag_data[:name], tag_data[:description]))
end
但是看起来很难看。说不清为什么。
2.
为标签创建单独的存储库。
# PostRepository
def find(id)
# getting post data from storage here
Post.new(title, text, tag_repository.find(tag_ids)) # or tag_names or tag_something
end
看起来好多了。但是为值对象创建单独的存储库可以吗?
根据DDD,正确的方法是什么?
更新:
另一方面,我必须获得所有可用的标签。而且我永远不必用 posts 更改标签。标签的名字看起来像身份。也许我从根本上是错误的?也许标签是实体?
UPD2:
这个问题说明我的设计功底很差。
因此,我的问题中有两个问题。
他们是:
- 在实体存储库中构建值对象的正确方法是什么。
- 如何在我的问题中看出值和实体之间的区别。
毕竟看起来很清楚。根据指定的条件,标签是值。没关系,它是由 Post 的存储库构建的。
但这种情况是分析不当造成的。如果我能看得更远一点,我会看到标签有它自己的生命周期。但是,在 post 的上下文中,标签是不可变的。
标签很可能只是您域中的常规值对象。标签可以是一个实体,如果它有自己的生命周期的话。坦率地说,我认为您的域不是这种情况,因为您可以将每个标签替换为具有相同属性的另一个副本。
您可以将查询标签的方法添加到您的域存储库中。这不违反 DDD 聚合规则。聚合实际上是关于一致性的——如果您可以在聚合上下文之外修改它们,那么您的存储库不应该是聚合的 return 部分。但是,您可以明确 return 仅出于阅读目的对聚合对象赋值(例如,收集选定日期范围内所有帖子的所有标签)。除此之外,为了提高效率,查询方法应该放在存储库中。话虽如此,在您的情况下,最好的解决方案可能是遵循 CQRS 原则使用单独的读取模型(使用例如 nosql db)。通过这种方式,您可以根据查询需求明确调整模型,因此它可以非常高效。
我刚刚开始学习DDD。所以我为愚蠢的问题道歉...
所以我有了 Post
实体。看起来不错。但它应该有 tags
。
在代码中它看起来像这样(ruby 代码):
class Post
attr_reader :tags
attr_reader :title
attr_reader :text
# ...
end
class Tag
attr_reader :name
attr_reader :description
# ...
end
标签作为实体没有意义。我不需要 tag
本身。
但是我应该如何为 post 实现存储库?
我发现了 2 个变体:
1. 在同一个存储库中构建标签。像这样:
# PostRepository
def find(id)
# getting post data from storage here
# getting tags data
Post.new(title, text, tags_data.map { |tag_data| Tag.new(tag_data[:name], tag_data[:description]))
end
但是看起来很难看。说不清为什么。
2. 为标签创建单独的存储库。
# PostRepository
def find(id)
# getting post data from storage here
Post.new(title, text, tag_repository.find(tag_ids)) # or tag_names or tag_something
end
看起来好多了。但是为值对象创建单独的存储库可以吗?
根据DDD,正确的方法是什么?
更新: 另一方面,我必须获得所有可用的标签。而且我永远不必用 posts 更改标签。标签的名字看起来像身份。也许我从根本上是错误的?也许标签是实体?
UPD2:
这个问题说明我的设计功底很差。 因此,我的问题中有两个问题。 他们是:
- 在实体存储库中构建值对象的正确方法是什么。
- 如何在我的问题中看出值和实体之间的区别。 毕竟看起来很清楚。根据指定的条件,标签是值。没关系,它是由 Post 的存储库构建的。
但这种情况是分析不当造成的。如果我能看得更远一点,我会看到标签有它自己的生命周期。但是,在 post 的上下文中,标签是不可变的。
标签很可能只是您域中的常规值对象。标签可以是一个实体,如果它有自己的生命周期的话。坦率地说,我认为您的域不是这种情况,因为您可以将每个标签替换为具有相同属性的另一个副本。
您可以将查询标签的方法添加到您的域存储库中。这不违反 DDD 聚合规则。聚合实际上是关于一致性的——如果您可以在聚合上下文之外修改它们,那么您的存储库不应该是聚合的 return 部分。但是,您可以明确 return 仅出于阅读目的对聚合对象赋值(例如,收集选定日期范围内所有帖子的所有标签)。除此之外,为了提高效率,查询方法应该放在存储库中。话虽如此,在您的情况下,最好的解决方案可能是遵循 CQRS 原则使用单独的读取模型(使用例如 nosql db)。通过这种方式,您可以根据查询需求明确调整模型,因此它可以非常高效。