问题标签 [anemic-domain-model]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
architecture - 这种“贫血”模型是否可以接受设计?
我首先想说的是,我并不想在我当前的设计中完成一个领域模型。
话虽如此,我目前正在构建一个如下所示的架构:
我一直在看Eric Evan 的 DDD 书,也看过Greg Young 的 DDD 项目失败的 7 个原因,害怕贫血模型。即使我没有规定 DDD,我也不想创建太多层,以致于来回映射非常相似的东西会变得很痛苦。
但是,我进行设置的全部原因有两个。易于更改和晦涩难懂
- 易于更改:如果我的公共对象通过我的服务公开,并且我在内部使用 UI 和业务对象,那么我可以在不破坏现有 API 的情况下更自由地进行更改。但是,如果 DTO 开始偏离,也许我可以使用一个 DTO 并重构?
- 模糊性:我可以公开我的公共对象,但如果它们是内部的,则不能公开我的完整对象及其实现。这将需要是一个安全的产品,所以我正在为此做准备。但是,也许我可以稍后再重构它?
所以,我的问题是:我当前的模型是否有意义,或者我稍后会提出问题?可以因为这些对象主要是 DTO 吗?即使在 Evan 的书中,他也暗示如果计划分布在不同的服务器上,这个模型是可以的吗?那么,仅出于这个原因,我的分层是否可行,因为我计划让 UI、服务和 DB 层能够位于不同的服务器上(由于当前不需要,它们目前还没有)?
我只是想了解过度架构,但同时试图避免架构不足.....那么,这个模型结构对我当前的实现是好还是坏?
lucene - 使用 Lucene 到 POCO 的 DTO
我们使用 Lucene 作为数据检索的搜索服务器。
随之而来的是一些我没有准备好的复杂性,其中最重要的是管理对象之间的关系。
我想为我们的域对象创建一个干净简单的 POCO。这些 POCO 将包含 UI 所需的相关对象,但没有其他字段(定义这些关系的 ID,UI 上根本不需要的各种其他字段)
这意味着我不能直接将 Lucene 的 Hits 集合转换为我的 UI 友好的 POCO,并且需要一些中间类集,这些类至少包含相关对象的 ID(存储在相同或其他索引中)。我不愿称这些 DTO 对象,但为了简单起见,我将它们称为。
所以我设想它的工作方式如下:
- 在 Lucene -> Hits 集合中执行查询
- 遍历 Hits -> DTO 集合
- DTO 集合 -> [检索相关对象的服务,组成 POCO] -> POCO
- 使用闪亮的简单 POCO 渲染 UI
我这样做的恐惧是我最终会得到贫血域模型(http://www.martinfowler.com/bliki/AnemicDomainModel.html)。
这是一个有效的担忧还是我走在正确的道路上?
asp.net-mvc - 域模型与服务层中的 ASP.NET MVC 业务逻辑
我一直在阅读有关在 ASP.NET MVC 项目中放置业务逻辑的位置一段时间,但我仍然无法弄清楚某些事情。
1域模型。这些到底是什么?在我的模型文件夹中,我只有一堆与我的数据库相对应的类。我首先使用 EF 代码。我假设这些是我的领域模型。
2-服务层。这个答案暗示了一个服务层,我认为这很有意义。我决定和这个一起去。然而,Martin Fowler 的“贫血域模型”文章让我大吃一惊。
我不确定如何向我的域模型添加逻辑。
我经历了许多与业务逻辑相关的问题,每个问题都提出了 1 或 2。我不明白如何实现第一个。向实体类(对我来说是域模型)添加方法根本没有意义。为什么第二种方法被认为不好?
entity-framework - 如何避免规则形式的业务逻辑贫乏的领域模型
我正在设计一个具有简单实体框架支持的域对象的系统,该对象具有我需要根据一系列规则更新的字段 - 我想逐步实现这些规则(以敏捷风格)并且当我使用 EF 时我持怀疑态度关于将每个规则放入域对象中。但是,我想避免编写“程序代码”和使用贫血的域模型。这一切都需要可测试。
例如,对象是:
我需要建立一些规则,例如“如果 Salary 高于 100,000 并且 _eligibleForPension 为 false,则将 _eligibleForPension 设置为 true”和“如果 _pension 为 true,则将 _eligibleForPension 设置为 true”。
大约有 20 条这样的规则,我正在寻找是否应该在 Employee 类或类似 EmployeeRules 类中实现它们的建议?我的第一个想法是为从“Rule”继承的每个规则创建一个单独的类,然后将每个规则应用于 Employee 类,可能使用访问者模式,但我必须将所有字段暴露给规则才能做到这一点感觉不对。虽然在 Employee 类上设置每条规则也感觉不太正确。这将如何实施?
第二个问题是实际的员工是支持数据库的实体框架实体,所以我不乐意为这些“实体”添加逻辑 - 特别是当我需要模拟对象以对每个规则进行单元测试时。如果他们有我在同一个对象上测试的规则,我怎么能嘲笑他们?
我一直在考虑在应用规则之前使用 AutoMapper 转换为更简单的域对象,但随后需要自己管理对字段的更新。对此也有什么建议吗?
java - 使用现有(第 3 方)数据模型 (Java) 的领域驱动开发
首先我想说的是,我开发软件的标准方法可能是许多开发人员的典型……我有行为丰富但没有状态的服务,我有只有状态而没有状态的对象(Bean)行为(我认为这通常被称为贫血域模型)。
我决定在一个新项目中尝试领域驱动设计 (DDD) 方法,但是我有几个问题确实让我很烦恼。
我有一个现有的第 3 方数据库,我的组织使用它(它与业务紧密耦合,对此我无能为力:我不希望有任何评论提及如果第 3 方更改他们的数据模型...我知道!!)。我创建了休眠实体来表示数据,但是我不确定如何将其转换为符合 DDD 原则的内部模型表示(即封装数据访问的富域模型)。
这类问题一定有模式,但我发现很难找到任何模式。这使我相信我可能以错误的方式做某事(即不是通常接近的方式)。
我目前的策略是:
- 识别休眠实体中的关键实体,并尝试将它们与相关的 Values 对象打包在一起(这真的很困难,我相信因为我从数据开始并创建一个域......关于方法的任何建议这也将受到欢迎)
- 对于我确定的每个包,我都创建了一个存储库来管理实体
- 在每个存储库(例如 StudentHibernateRepository)中,我抓住我需要的休眠实体并将它们包装在一个代理类中。
- 在每个代理类中,我添加了我的业务规则,这些规则通过使用包装的休眠实体作为数据源(再次尝试使我的代码行为丰富)。
如果有人有做类似事情的经验,请您分享经验/模式。如果您能反思一下我所采取的策略,那也会很有帮助。
干杯,
爱
domain-driven-design - 将域模型标记为贫血的标准是什么?
到目前为止,我还没有看到一篇博客文章或文章描述了将域模型标记为贫血的客观标准。我认为,为贫血领域模型设定客观标准肯定会有所帮助。
几年前,我设计了一个领域模型。我在数据库中有几个表(大约 7 个)。我在代码中创建了完全相同数量的类。我为这些类中的每一个实现了存储库模式。今天,我绝对觉得它是贫血的领域模型。我有机会设计一个面向对象的领域模型,但我设计的领域模型本质上是关系型的。从那次经验来看,我定义的一个标准是——如果对象模型与你的关系模型一对一地映射,那么它可能是领域模型贫乏的标志。
是否有任何其他标准可能指向贫血域模型?
谢谢。
oop - RDM vs ADM(再次)或者中间立场在哪里?
在网上(和书本)上花费了无数小时试图得出关于这个主题的结论,查看了许多人的观点,以及试图权衡利弊的不同方面之后,我决定发布一些我认为的关键问题希望比我聪明的人回答:)
我阅读了 Martin Fowler 关于 ADM(他称之为贫血域模型)的文章以及书籍,并且我了解 Eric Evan 的 DDD(域驱动设计)。他们是非常受人尊敬、经验丰富的建筑师,他们在将所有这些知识汇编成他们的书籍和文章方面做得非常出色,但是(我知道这几乎是不可能做到的,因为在所有印刷媒体中都是如此)他们的例子是通常非常清晰,可以解释一个概念,但不幸的是很难将它们用于现实生活中。
在这里,我将快速解释一些我对您在 (RDM / ADM+TS(Service)) 中的选择非常感兴趣的案例,让我们假设一个 IoC 容器正在执行布线(尽管它大多无关紧要):
案例一/1:
任务:下订单
ADM+TS:
要求:
Order oject - 数据(set+get)(类似 DTO 的“数据包”)
OrderService - 操作(对实体对象的类似 TS 的操作)
RDM:
要求:
订单对象 - 数据和功能(丰富)
案例一/二:
任务:下订单并在其后发送电子邮件
ADM+TS
要求:
Order oject - 数据(set+get)(类似 DTO 的“数据包”)
OrderService - 操作(对实体对象的类似 TS 的操作)
EmailService - 发送电子邮件
(可选) OrderServiceEmailDecorator - 分离实际放置的关注点订单,并发送电子邮件
评论:
解决方案:
a。使用现有的 OrderService 并向其添加电子邮件,在这种情况下,OrderService 依赖于 EmailService
b。将关注点分离到一个装饰器中,我们可以将其与 IoC 中的服务连接在一起,并根据我们是否需要按需使用
RDM:
要求:
订购项目 - 数据和功能(丰富)
?EmailService - 发送电子邮件
?EventHandler - 捕捉事件
评论:
嗯,在这种情况下,人们通常会推荐以下内容
:“将您的依赖项注入域层”:这将使域层非常沉重,并且到处都是依赖项。
湾。“将服务与 place(...) 调用一起传递”:随着越来越多的依赖项进入它,这将使函数签名一直发生变化。
C。“引发一个重要操作已完成的事件”:即使是最强大的 RDM 倡导者也说持久性不应该直接存在于域模型中,这意味着我们在这里引发了一个事件,但是该操作并未完全执行(持久化)。所以我们可能会在完成之前发送一封电子邮件。我们可以说电子邮件可能会失败,所以它不是完美的,但我认为实际上下订单是这里的主要操作,发送电子邮件只是一个通知,而且,可以重复,加上你在屏幕上通知等。你明白了,真的,下订单并不依赖于能够发送通知电子邮件,但如果坚持订单失败,你肯定不想发送电子邮件。但是有些人可以说,在它被持久化的存储库中引发类似的事件,
案例一/3:
任务:可以批量下订单,我们只想发送一封包含所有订单的通知电子邮件(请不要开始评论这些只是同一个订单上的项目,这是一个例子)。
ADM+TS
要求:
Order oject - 数据(set+get)(类似 DTO 的“数据包”)
OrderService - 操作(对实体对象的类似 TS 的操作)
BulkOrderService - 将取决于 OrderService(非修饰)
EmailService - 发送电子邮件
BulkOrderServiceEmailDecorator -依赖 EmailService 发送聚合邮件
评论:
我们不使用装饰的 OrderService,而是使用(装饰的)BulkOrderService
RDM:
要求:
订购项目 - 数据和功能(丰富)
?EmailService - 发送电子邮件
?EventHandler - 捕捉事件
评论:我们的域对象现在变得有点复杂了,我们不能在上面放一个 .bulkPlace() 因为显然我想在同一个上下文中放置多个订单,所以逻辑必须存在一层,比如说在控制器级别,并在每个订单上调用每个 place(),在这种情况下:从上面继续(基于 I/2 RDM 解决方案)
:(“注入的依赖项”)我们如何绕过这里发送的电子邮件?现在我们需要一个 .placeWithEmailAndAnyOtherDependency.. 和一个 .placeWithout...?您不能将域对象完全装饰为公平
b。(“通过服务”)现在,如果你通过 null 而不是它不会发送电子邮件的服务,你也许可以这样做(但这看起来很狡猾)
C。(“引发事件”)这是一个问题,现在我们将电子邮件发送绑定到此事件,并且我们希望重用 .place() 调用,即使在批量订单中也会发送多封电子邮件,除非我们可以以某种方式分离它(也不能真正装饰存储库)
现在这些问题中的一些可能可以用 AOP 而不是装饰器来解决,但仍然感觉很hackish。
案例 I/4:
任务:现在我们有多个入口点,因为我们希望能够从我们的调度程序“调度”重复的批量订单,但也希望直接在我们的网站上保留此功能。(或者我可以说我们希望拥有一个控制台客户端以及 Web 客户端,关键是我们的 Web 控制器不会完成这项工作,无论如何都不会直接完成)
ADM+TS
要求(未更改):
订单对象 - 数据(set+get)(类似 DTO 的“数据包”)
OrderService - 操作(对实体对象的类似 TS 的操作)
BulkOrderService - 将取决于 OrderService(未修饰)
EmailService - 发送电子邮件
BulkOrderServiceEmailDecorator - 依赖 EmailService 发送聚合电子邮件
评论:我们没有使用装饰的 OrderService,而是使用(装饰的)BulkOrderService - 基本上没有任何变化
RDM:
要求:
订购项目 - 数据和功能(丰富)
?EmailService - 发送电子邮件
?EventHandler - 捕捉事件
评论:取决于我们在 I/2 中所做的,与 I/3 相同的问题仍然适用,但最重要的是,我们不能再使用我们的控制器来循环命令,或者如果我们这样做,它会变成类似的东西一个 TS,我们又回到了与 ADM+TS 类似的分层架构
所以,我的主要问题是我自己在 RDM 中找不到一个明确的、非常合适的解决方案来解决像这样的简单问题,即使在阅读和谷歌搜索之后人们推荐了不同的东西,这些东西可以很好地解决一件事,但是出血另一个,而 ADM+TS 解决方案在处理它们时感觉更灵活。(更不用说您不需要 DTO-s,因为您的 ADM 本质上就是您的 DTO,您可以将事件传递给视图 - 因此无需进行任何转换)
如果您对如何以合适的方式使用 RDM 处理(逐步)案例 I/2 和 /3 有意见,请发表评论,但如果您这样做,请提供并回答所有问题(所有 4 ,或者至少是最后 3 个,因为 1 并不是真正的问题)!不仅仅是那些你有一个方便的答案(比如一半的任务/等等)
谢谢
更新: 看到一些答案,我可能应该选择一个不同的“实体”,然后是这个练习的著名命令(我只是想选择一个熟悉的)。无论如何,作为补充,试着想象案例 I/2、I/3、I/4 不是初始要求,它们是有机地进化的。这些要求是逐步添加的。所以首先你被告知只要有订单就发送一封电子邮件,现在如果你以任何方式将它们结合在一起,当 I/3 与批量订单命中时你会遇到问题。即使您只是将电子邮件放在消息总线上,而它还没有发送,您会如何批量处理?然后您将消息放在总线上然后将其删除/进行清理?或者应该触发基于 I/2 的任何其他操作,但基于 I/3,不再适用,无论如何都要执行它们然后恢复它们?这听起来不对
.net - 域对象 - “智能对象”与 POCO
通过智能对象,如果属性被更改,我会考虑任何知道其原始属性值的域对象。智能对象通常有一个基类并通过使用 GetPropertyValue/SetPropertyValue 方法来实现属性。另一方面,POCO 对象通常没有基类并实现简单的属性。
我喜欢智能对象,因为它为我做了很多艰苦的工作。我可以轻松地将所有这些有用的功能添加到 BaseDomainObject 并将它们放在我所有的派生域类中:
- 常用属性(如 Id、Status...)
- 对象状态跟踪(新的、修改的、未更改的)
- 所有属性都会引发属性更改事件(INotifyProperyChanged 的实现)
- 派生类可以自动序列化(虽然我很少发现这很有用)
- 我可以拥有所有其他有用的行为 - 克隆/同步/IsPropertyDirty...
另一方面,POCO 非常简单,不依赖于任何基类。
现在我在这里有很多 POCO 称赞,因为:
- 它可以通过网络发送(通常以 JSON 格式发送到 Web 浏览器)
- 它是纯的
另一方面,我认为上述原因是谬误的,因为:
- DTO 用于电汇而不是域对象。当域对象序列化为 JSON 时封装数据的行为。
- 这种追求纯度接缝就像追求更加贫乏的领域模型,它没有逻辑,也没有任何智能附加在它上面。
带着这一切悲伤,我仍然喜欢那个 POCO,它让我很烦恼。你有什么意见?
design-patterns - EAA P 中的领域模型和服务层模式
在企业应用架构模式中,Martin Fowler 谈到了组织领域逻辑的两种模式:领域模型和服务层。领域模型模式是“纯 OOP”方法,其中模型(可能使用 ORM 从数据库中查找的那些对象)包含业务逻辑(尽管可能只委托给另一个类中的逻辑)。
服务层模式类似于域模型模式,但在它前面有一个薄层,包含可以执行的业务操作。在 MVC 中,控制器主要与服务层交互。我相信大多数设计良好的 MVC Web 应用程序都使用这种模式。
现在,我的问题。Martin 建议域模型方法是更面向对象的方法,因此更好。以我的经验,在实践中实施非常困难(参见:不可能)。
以上面第一张图中给出的例子为例。有两个“实体”Contract
和Product
。这些通过映射器持久化到数据库中。在示例中,有一个RecognitionStrategy
. Martin 将委托给包含实际业务逻辑的策略的方法放在实体本身中;contract.calculateRecognitions
客户端使用or执行此计算contract.recognizedRevenue(someDate)
。在实现类似的设计时,我通常将客户端界面编写为strategy.calculateRecognitions(contract)
和strategy.recognizedRevenue(contract, someDate)
。这使得服务层对于协调策略和合同是必要的。使用的具体策略被注入到服务中。
从设计的角度来看,Martin 的方法肯定更具吸引力,但围绕设置的工作要困难得多:
- 在实例化 a 时传递策略
Product
是一种痛苦。您需要Product
通过带有要使用的具体服务的工厂来创建 s,然后在创建实体时将其传递给实体。 - 对数据库访问的细粒度控制较少。根据 ORM 设置,
Contract
委托给Product
每个Product
. 当我们加载Product
aContract
但不打算调用contract.calculateRecognitions()
. 我的方法为我们提供了更细粒度的控制,因为服务具有数据库抽象层的知识,而实体不应该。
我敢肯定,在实践中还有更多的痛点我在这里没有一一列举。
Martin 的方法有哪些具体优势可以说服我使用纯数据模型模式?