我一直在阅读Evans关于DDD的书,并在思考如何在.NET中实现聚合。目前,我只能想出一种方法。将聚合隔离在单独的类库中。但是,这似乎有点矫kill过正(我宁愿将所有域对象都保留在一个库中),并且我想知道是否有其他方法吗?
1 lib/aggregate的理由如下:聚合根需要知道对其负责的“子对象”的所有访问,并且聚合根还可以作为其成员的结果返回子对象。因此,这些子对象的成员(需要聚合根)无法公开。因此,您唯一的选择是将它们设置为内部(因为它们仍需要由聚合根调用)。但是,通过将所有聚合放入一个项目中,仍然可以从已获得子对象的其他域对象访问这些成员。这是不希望的,因为它允许绕过聚合根。通过分离不同库中的所有聚合,可以解决此问题。
一些其他信息:
我已经检查了DDD java sample code,它们将每个集合(包括所有子对象的类)打包在一个不同的包中。只能从聚合根调用的成员没有访问修饰符(例如:Delivery.updateOnRouting)。在Java中,没有访问修饰符的成员是package-private(仅可从同一软件包中获得)。因此,这将是正确的行为。
但是,.NET sample code将所有域对象放在一个类库中,然后将相应的成员公开。对我来说,这似乎是不正确的。
最佳答案
聚合是DDD中最困难的概念之一。您拥有大部分权利。我建议以“成员身份”的形式总体表达这个概念比引入“子对象”这一术语更为直接。
是的,一个对象不能是多个集合的成员。哪一个是最终的执行者?一个聚合根可以通过删除成员并孤立另一个聚合中的其他成员来轻易使另一个根失效。您是正确的,在一个对象似乎需要多个聚合成员的情况下,该对象必须是一个独立的实体,即它成为新聚合的根。 (它可能有也可能没有其他成员,但是如果没有,则它当然是它自己的一个成员的集合。)
是的,绝对存在强制执行不变性的集合。就持久性而言,它也是单个工作单元或单个事务。聚合根最终负责整个成员中的所有不变量,这必须是因为,例如,不变量的失败可能导致持久性失败,并且聚合负责将聚合作为一个可行的持久性工作单元维护。
但是,这是一个微妙而困难的部分,最终责任并不意味着合计也是主要强制实现者。就像我们在司法系统中所拥有的一样,法院最终是确定法律问题和施加最终法律规则的最终场所,而不变性则被强制执行。但是实际的执行(和遵从性)发生在系统的许多级别。实际上,在一个秩序井然的社会中,大多数实现法治的 Activity -对不变量的执行-应该早在上法庭之前就已经发生了,甚至根本不必依靠常规去上法庭。 (尽管在DDD中,您可能总是希望有一个聚合根,例如在持久性之前进行最后的不变扫描。)
您的建议是完全不同的,除了法院之外,您的整个社会实际上都被监禁了,您似乎甚至建议其他人甚至不能访问,他们只能向法院传递信息并希望它能适本地发挥作用。
让我们看看如果您按照建议的方式对您的域进行了处理。目的是创建一个丰富而富有表现力的领域模型。在有意义的普遍存在的语言方面,您已经将工作词汇量减少到了总的根。实体之所以应该被聚合根访问是因为不变量,而且还因为如果设计正确,则该实体具有有意义的身份,该身份是由于其在聚合根上下文中的成员身份而产生的。但是您的提案实体在其聚合根之外甚至没有任何类型标识。 Evans特别指出,这是聚合根的目的的一部分-允许对象通过遍历获取对成员的引用。但是您无法获得有用的引用,因为另一个对象甚至都不知道您的成员类型存在。或者,您可以更改 namespace ,但是如果您不允许遍历,那就更好了。现在,您的整个域都知道类型,但是无法获得对象的类型。
更糟糕的是您的聚合根发生了什么。聚合根除了维护聚合完整性外,通常还应有其自身存在的理由。但是现在这种身份不再明确。对于所有各种元素及其属性都需要有一个包装方法,这使它变得晦涩难懂。您得到的是不再具有表现力甚至清晰的身份的聚集的根,而只是庞大而笨拙的上帝对象。
您的Order和OrderLine示例就是一个有趣的例子。订单未执行代表订单行的订单行所需的某些不变式的强制执行。在这种情况下,它控制 Action 以强制执行自己的不变式。这是对聚集根进行 ionic 控制的有效措施。但是,更通常地,聚集大多数情况下与对象的创建和/或破坏有关。
当然,没有必要强加一个模型,在该模型中,状态的所有变化都必须由聚合根自动应用,而绝不能直接应用。实际上,这通常就是为什么聚合根允许遍历以获得对成员的引用的原因-外部对象可以应用状态更改,但是在聚合控制着更改的成员实体的实例生命周期的上下文中。
对于开发丰富而富有表现力的模型而言,不仅可见度,而且与更大范围的实际交互通常是基础。聚合用于控制该访问,但不能完全消除该访问。
我希望这会有所帮助,这是一个很难讨论的概念。
关于java - .NET中的DDD/聚合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6588792/
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时
作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代
Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题
我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何
我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer
刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr
是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou
我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢
我注意到像bundler这样的项目在每个specfile中执行requirespec_helper我还注意到rspec使用选项--require,它允许您在引导rspec时要求一个文件。您还可以将其添加到.rspec文件中,因此只要您运行不带参数的rspec就会添加它。使用上述方法有什么缺点可以解释为什么像bundler这样的项目选择在每个规范文件中都需要spec_helper吗? 最佳答案 我不在Bundler上工作,所以我不能直接谈论他们的做法。并非所有项目都checkin.rspec文件。原因是这个文件,通常按照当前的惯例,只