我只是想查找Martin Fowler的域模型模式的一些示例,但我找不到。
从我在Internet Domain Model上发现的内容来看,只是在类中添加了一些“逻辑”方法。例如
public class Income { private String title; private String comment; private String date; private Double amount; private Integer category; public ExIn(String title, String comment, Double amount, Integer category, String date) { this.title = title; this.comment = comment; this.date = date; this.amount = amount; this.category = category; } public Integer getCategory() { return category; } public void setCategory(Integer category) { this.category = category; } // more getters and setters // Domain Model part starts public boolean isPositive() { return amount > 0 ? true : false; } // more methods like that }
我理解正确吗?如果不是这样,我将不胜感激地举一个域模型模式用法的小例子。
我理解正确吗?如果没有,我将举一个例子。
大致上是。
对于Martin Fowler而言, 领域模型是领域的对象模型,其中包含行为和数据 。 域模型经常与模型相对,在模型中,您有特定的类来承载数据,而其他一些特定的类来承载行为/处理。
如果我参加您的Income课程,它看起来更像是一个拥有属性/数据的类,而不是具有真实行为的域模型。
Income
public boolean isPositive(){ return amount > 0 ? true : false; }
是一种与模型无关的效用函数。 您可以将其放在Math课堂上。
Math
我将尝试为您提供一个域模型示例,然后再提供该模型将数据和处理分开的版本。
假设您要建模的应用程序领域的需求中,我们需要为收入增加奖金。例如,此奖金可能发生在圣诞节的冬季(但为什么不参加其他活动)
让域模型对象执行任务,而不是让服务类进行此处理。
Incomes,高级对象可以在Income实例上进行迭代并应用奖励,我们可以有一个奖励规则类,该规则类根据一些输入值定义奖励。 我介绍了多个类,因为这种想法是允许每个对象根据其职责进行协作。
Incomes
收入:
public class Incomes { List<Income> incomes = ... .... public void applyBonus(BonusRule bonusRule){ for (Income income : incomes){ income.applyBonus(bonusRule); } }
public class Income { private float amount; ... public void applyBonus(BonusRule bonusRule){ float bonus = bonusRule.compute(this); amount += bonus; } ... }
ChristmasRule:
public class ChristmasBonusRule implements BonusRule { ... @Override public float compute(Income income){ float bonus = ... return bonus; } ... }
最后,我们可以通过以下方式进行处理:
void foo(){ // create a domain object that has both behavior and data Incomes incomes = ...; // invoke a functional method on the object by passing another domain object incomes.applyBonus(new ChristmasBonusRule()); }
在将数据和逻辑划分为不同类的设计中,它看起来像这样:
public class IncomeBonusService { // stateless : no incomes data inside it .... public void applyChristmasBonus(List<Income> incomes){ for (Income income : incomes){ // Christmas bonus computation here float bonus = ... income.setAmount(bonus + income.getAmount()); } } }
我们可以这样处理:
// inject the service @Autowired IncomeBonusService incomeBonusService; void foo(){ // create a domain object that has only data List<Income> incomes = ...; // invoke a service method by passing data as parameter incomeBonusService.applyChristmasBonus(incomes); }
对象没有任何行为(只有getter / setter)的模型设计称为Anemic Domain Model。
此示例说明的两种方式之间的巨大差异:
领域模型:
对象是有意义的。
在班级之间明确定义了行为责任。 因此具有良好的隔离性,可测试性和可维护性。 例如,添加/删除/单元测试a BonusRule很容易。
BonusRule
对象负责其状态。 的确,由于对象本身可以在与其他对象协作之后更新其状态,因此无需提供设置器。 我们可以在中看到Amount.applyBonus():
Amount.applyBonus()
float bonus = bonusRule.compute(this); amount += bonus;
贫血领域模型:
所有逻辑都在服务类中。 因此,一个地方即可获取代码。 只需几行,就可以了。 但是请注意,这种优势有一定的局限性,因为随着逻辑变得庞大或复杂,最好的事情通常是将逻辑拆分为多个服务类。
但是,无论您需要多少服务类,整个逻辑都位于服务类中,而不是其他位置。如果我们将其与可能在某些不同的“类型”类中分解逻辑的领域模型进行比较,则可以简化开发规范。
为域类提供获取/设置程序的必要性。 该域也不负责其状态及其不变规则。 因此,任何依赖域类的类都可以“破坏”其状态。
附带说明一下,默认情况下,某些框架(用于持久性,映射,序列化等)依赖于getter / setter。 这就是为什么这种模型尽管有缺点,但却在某些项目中处于领先地位的原因。