我正在努力理解DDD背后的概念,但我发现通过阅读书籍很难理解,因为他们倾向于以相当抽象的方式讨论这个主题.我希望在代码中看到一些优秀的DDD实现,最好是在C#中.
在开源世界中有没有很好的DDD项目实例?
我在一些DDD企业应用程序中看到的一件事是,使用与域实体相同的接口,以及属性和功能的一对一映射.实际上,域对象总是通过它的一对一接口使用,并且所有域实体都具有这种风格的一对一接口.
例如:
域对象帐户:
public class Account : IAccount
{
public string Name {get;set;}
//...some more fields that are also in IAccount
public decimal Balance {get;set;}
}
Run Code Online (Sandbox Code Playgroud)
它是匹配的界面
public interface IAccount
{
string Name {get;set;}
//... all the fields in Account
decimal Balance {get;set;}
}
Run Code Online (Sandbox Code Playgroud)
但最近我越来越相信这实际上是一种反模式.
我是由开源社区的一些架构师运行的,他们说这是基于设计错误或缺陷,在设计链的某个地方.
所以我告诉我的同事他们应该退出为Domain对象创建接口.因为它们没有任何意义,所以每当更新域实体时都必须更新接口.
首先声称这些接口提供了"解耦",但我反驳说,因为接口与域实体有一对一的关系,它们实际上并没有提供任何解耦,接口的改变意味着改变域实体,反之亦然.
下一个主张是我们需要接口用于测试目的.我的反击是Rhino-mocks提供了具体类的模拟和存根.但是他们声称Rhino-mocks在具体课程方面遇到了麻烦.我不知道我是否购买,即使rhino-mocks在具体类中遇到问题,也不一定意味着我们应该使用域实体的接口.
所以我很好奇:
为什么你的域实体有一对一的接口?
为什么不?
为什么这是一个好的或坏的做法?
谢谢阅读!
编辑:我应该注意,我一直使用接口,我相信如果它被要求我将使用一个接口.但我特别指的是具有一对一接口的域实体.
我最近开始阅读Evans的Domain-Driven设计书,并开始了一个小样本项目,以获得DDD的一些经验.同时我想了解更多关于MongoDB的知识,并开始用MongoDB和最新的官方C#驱动程序替换我的SQL EF4存储库.现在这个问题是关于MongoDB映射的.我看到用公共getter和setter映射简单对象非常容易 - 没有痛苦.但是我在没有公共设置者的情况下映射域实体有困难.据我所知,构建有效实体的唯一真正干净的方法是将所需的参数传递给构造函数.请考虑以下示例:
public class Transport : IEntity<Transport>
{
private readonly TransportID transportID;
private readonly PersonCapacity personCapacity;
public Transport(TransportID transportID,PersonCapacity personCapacity)
{
Validate.NotNull(personCapacity, "personCapacity is required");
Validate.NotNull(transportID, "transportID is required");
this.transportID = transportID;
this.personCapacity = personCapacity;
}
public virtual PersonCapacity PersonCapacity
{
get { return personCapacity; }
}
public virtual TransportID TransportID
{
get { return transportID; }
}
}
public class TransportID:IValueObject<TransportID>
{
private readonly string number;
#region Constr
public TransportID(string number)
{
Validate.NotNull(number);
this.number = number;
} …Run Code Online (Sandbox Code Playgroud) 我刚刚开始使用DDD,所以这可能是个愚蠢的问题......
是否可以让实体访问存储库(通过某个IRepository接口)在运行时获取值?例如,我想对属性强制执行"默认"选择:
class Person {
private Company _employer;
public Company Employer {
get { return _employer; }
set {
if(value != null) {
_employer = value;
} else {
_employer = employerRepository.GetDefaultEmployer();
}
}
}
...
}
Run Code Online (Sandbox Code Playgroud)
我的问题是,做这样的事情是对DDD原则的可怕违反.如果不是,我的下一个问题是提供存储库使用的最佳方式是什么?是否应该在创建Person对象时提供?
谢谢,P
在PHP中编程时,我总是尝试创建与数据库中的表对应的有意义的"模型"(类).我经常遇到以下问题:
假设我已经创建了一个包含两个表的数据库:authors并且blogs在我的应用程序中都有相应的模型.
假设我想打印所有博客以及有关作者的信息,我必须做这样的事情:
<?php
foreach ($app->getBlogs() as $blog) {
echo "<h1>" . $blog->title . "</h1>";
echo "Written by" . $blog->getAuthor()->name . "</p>";
// ... et cetera
}
?>
Run Code Online (Sandbox Code Playgroud)
问题是,应用程序现在将触发1个SQL查询以获取所有博客项目和[博客项目数]查询以获取每个作者的信息.使用简单的SQL我可以使用简单的查询检索此信息:
SELECT * FROM blogs
JOIN authors ON authors.id = blogs.author
Run Code Online (Sandbox Code Playgroud)
处理此类问题的最佳方法是:开发面向对象的应用程序而不执行太多无用的SQL查询.
实际上我对这些术语以及它们如何相互关联感到非常困惑.阅读关于他们每个人的事情,但我不了解工作流程..
DTO - 数据传输对象 - 传输值的
对象BO业务对象 - 域模型中的对象.使用
POCO 创建业务逻辑的对象- 不知道,我已经阅读了维基上的定义,但没有理解任何东西
DAO - 数据访问对象 - 映射数据库表的对象?
请有人请为我带些光吗?
我有关于DDD和存储库模式的问题.
假设我有Customer聚合根的Customer存储库.Get&Find方法返回完全填充的聚合,其中包括Address等对象.一切都很好.但是当用户在UI中搜索客户时,我只需要聚合的"摘要" - 只是一个包含汇总信息的扁平对象.
我可以处理的一种方法是正常调用存储库中的find方法,然后在应用程序层中将每个客户聚合映射到CustomerSearchResult/CustomerInfo DTO,并将它们发送回客户端.
但我的问题是性能; 每个Customer聚合可能需要多个查询来填充所有关联.因此,如果我的搜索条件与50个客户相匹配,那么在数据库中可能会检索到我甚至不需要的数据.
另一个问题是,我可能希望在客户的聚合根边界之外包含有关客户的汇总数据,例如最后一个订单的日期.订单有自己的聚合,因此要获取客户的订单信息,我必须调用OrderRepository,这也会降低性能.
所以现在我觉得我有两种选择:
向CustomerRepository添加一个额外的Find方法,该方法通过执行一个有效的查询来返回这些摘要对象的列表.
创建一个专门构建的只读CustomerInfoRepository,它只有1中描述的find方法.
但这两种感觉都让我觉得我违背了DDD的原则.我的存储库继承自通用基础:存储库,其中T:IAggregateRoot.这些摘要信息对象不是聚合,并且与T的类型不同,所以#1真的违背了设计.
也许对于#2,我会创建一个没有IAggregateRoot约束的抽象SearchRepository?
我的域中有许多类似的场景.
你会如何实现这种情况?
谢谢,戴夫
更新
在阅读Theo的答案之后,我想我会选择#2选项并在我的基础架构中创建一个专门的SearchRepository,以适应这些场景.然后,应用程序层(WCF服务)可以调用这些直接填充摘要DTO的存储库,而不是将域实体映射到DTO.
****更新2****
虽然我在一年多前问过这个问题,但我想我只是补充说我已经发现了CQRS,它旨在解决这个问题.Udi Dahan(http://www.udidahan.com/)和Greg Young(http://codebetter.com/gregyoung/)已经写了很多关于它的文章.如果您使用DDD创建分布式应用程序,CQRS适合您!
.net c# domain-driven-design ddd-repositories repository-pattern
如果我有一个Order类作为聚合根和1000个行项.
如何只加载1000个订单项中的一个?据我所知,订单项只能通过Order类访问,并具有"本地"标识.我还会在OrderRepository中创建一个像"GetLineItemById"的存储库方法吗?
编辑评论答案: 目前我不认为有一个不可变的孩子是合理的.如果我的Customer类包含多个地址,合同以及更多子集合,该怎么办?我想要执行CRUD方法的庞大实体.
我会
public class Customer
{
public IEnumerable<Address> Addresses { get; private set; }
public IEnumerable<Contracts> Contracts { get; private set; }
...
}
Run Code Online (Sandbox Code Playgroud)
如果用户纠正地址或合同财产的街道,我是否必须这样做?
public class Customer
{
public void SetStreetOfAddress(Address address, street){}
public void SetStreetNumberOfAddress(Address address, streetNumber){}
}
Run Code Online (Sandbox Code Playgroud)
然后,客户类将充满子操作方法.所以我宁愿这样做
addressInstance.Street = "someStreet";
Run Code Online (Sandbox Code Playgroud)
我想我误解了整个概念.. :)
.net nhibernate design-patterns domain-driven-design repository
在使用事件源聚合后端构建在DDD原则的环境中,如何将单独的聚合根(AR)相互通信?
例如,我有一个Facility聚合根(AR),它有一个负责创建BookingAR 的工厂方法.这Booking是PersonAR和FacilityAR 的时间敏感组合.A Person只能预订一个Facility.
在DDD中,我会保留对Bookingin Person和Personin的引用Facility.但是,当生成用于事件源的事件时,我认为尝试从后端处理事件反序列化将变得令人望而却步.因此,我只采用了对基于对象的值唯一id的引用.然而,这会带来一个新问题,当AR上的方法需要在另一个AR上调用另一个方法时 - 您如何处理这种情况?从域AR命中事件源存储库?
这种情况下的一般用例是什么?我接近这一切都错了吗?
我正在使用ASP.NET Webforms + EF4开始一个新的Web项目.我正在尝试按照本教程应用具有工作单元模式的存储库模式:http://www.dotnetage.com/publishing/home/2011/07/05/6883/the-repository-pattern-with-ef -code先dependeny喷射在-ASP净mvc3.html
我想我有了这个想法,但我的问题是,当我在模型中创建一个新对象时,我是否还必须在工作单元的IDALContext中定义该对象?这不是一个快速发展的手?此外,如果您与多个开发人员合作,并且如果您不希望其他开发人员看到您的DAL,您如何管理它?因为在我理解的模式中,当您在模型中创建新对象时,您还必须在本教程的IDALContext中定义它.对不起,我很困惑.
c# ×4
.net ×2
architecture ×2
cqrs ×1
dns ×1
dto ×1
interface ×1
mongodb ×1
nhibernate ×1
oop ×1
open-source ×1
php ×1
repository ×1
sql ×1
unit-of-work ×1