我只是想找到一些Martin Fowler的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
}
我理解正确吗?如果没有,我会感激一下Domain Model Pattern的一个小例子。
答案 0 :(得分:12)
我理解正确吗?如果没有,我会感激一点 示例
广义上说,是的。
从Martin Fowler开始,域模型是包含行为和数据的域的对象模型。
域模型经常与您具有承载数据的特定类的模型以及承载行为/处理的一些其他特定类相对。
如果我使用你的Income
类,它看起来更像是一个包含属性/数据的类而不是具有真实行为的域模型。
public boolean isPositive(){
return amount > 0 ? true : false;
}
是一种与模型无关的效用函数
你可以把它放在Math
课程中。
我将尝试为您提供域模型示例,然后是模型分离数据和处理的版本。
假设在您正在建模的应用程序的域的要求中,我们需要为收入添加奖金。例如,这个奖金可以在圣诞节的冬天进行(但为什么不用于其他活动)
我们让域模型对象执行任务,而不是让服务类来执行此处理。
Incomes
,高级对象可以在Income
个实例上进行迭代并应用奖励,我们可以根据某些输入值设置奖励规则类来定义奖励。
我介绍了多个类,因为这个想法是允许每个对象根据他们的职责进行协作。
收入:
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。
此示例说明的两种方式之间存在巨大差异:
域名模型:
对象很有意义。
课程之间精确定义的行为责任
如此良好的隔离性,可测试性和可维护性
例如,添加/删除/单元测试BonusRule
很容易。
负责其州的对象
实际上,不需要提供setter,因为在与其他对象协作后,对象本身可以更新其状态
我们可以在Amount.applyBonus()
中看到:
float bonus = bonusRule.compute(this);
amount += bonus;
贫血领域模型:
所有逻辑都在服务类中 所以一个地方可以获得代码 几行,很好 但请注意,这种优势有一定的限制,因为随着逻辑变得庞大或复杂,最好的事情往往是在多个服务类中拆分逻辑。
但无论您需要多少个服务类,整个逻辑都位于服务类中,而不是其他位置。如果我们将它与可能在类的某些不同“类型”中爆炸的逻辑域模型进行比较,这可能会简化开发规范。
为域类提供getter / setter的必要性
域名不对其州及其不变规则负责。
因此,任何依赖于域类的类都可以“破坏”其状态。
作为旁注,一些框架(用于持久性,映射,序列化......)默认依赖于getter / setter。
这就是为什么这个模型尽管有其缺点,但在一些项目中也是如此。
答案 1 :(得分:6)
您引用的Fowler的书中引用Larman's book作为介绍性理解和示例。
有趣的是,Larman的域建模方法并没有向域类添加行为。
域模型中有一个概念,即类是概念而不是软件类,但软件类基于域(概念)类。 Larman实施行为的方法遵循responsibility driven design和GoF设计模式。
域模型仍然是软件开发过程中的一个独立元素。这种建模方式的好处在于您将问题与解决方案分开。域模型应该适用于问题(从问题域捕获需求而不解决实现细节)。
Larman提出“操作合同”作为确保行为在域模型中保持一致的一种方式。同样,合同应该独立于解决方案(实现)。合同具有后置条件,在操作发生后描述域模型中的约束。后置条件的示例是当顾客在商店中完成购买时,销售对象与顾客购买的每个商品相关联。
业务逻辑的实现应该遵守为域模型定义的合同(后置条件)。 Larman使用Controller GRASP pattern以及其他GRASP模式的方法最终将此逻辑放在各种类中(通常是域层,这是受域模型中的概念类启发的软件类)或处理的façade(Controller)类系统运作。
Larman的方法比这个解释更复杂,但重点是行为永远不会仅仅在域模型中定义为方法。 Larman多次说域(概念)类没有方法,因为它们不是不是软件类。
福勒的书也提到了他在Analysis Patterns上写的另一本书的例子。模式来自各个领域,包括医疗保健,金融交易和会计。每个模式都以文本方式和简单的UML前符号描述(本书是在UML稳定为可用形式之前编写的)。
该书中的所有例子都没有显示软件类,即使用编程语言定义的方法(我能找到)。
我至少知道one book,其中分子生物学等领域的领域模型已经用UML发布。这是一个例子(注意UML被修改 - 子类型框显示在超类型框中 - 以节省空间):
上面的书没有对行为进行建模,可能是因为它们确实依赖于软件应用程序的要求。这些模型捕获了一些业务规则,例如:
- 每种化学配方必须由2种或更多种化学元素或化合物或两者组成。
但该书中的模型主要是数据模型。
谷歌搜索会找到你this huge model for the Biomedical Research Integrated Domain Group (BRIDG)。例如,向下钻取到分子生物学子域和类Gene
,您将看到它没有行为,也没有此域模型中的任何其他(概念)类。
Larman的哲学清楚地表明它们与编程语言无关(概念而不是软件类),作为代码中的单独工件,将它们明确地与问题联系起来域(要求)。
另一方面,你会发现Fowler说"I prefer POJO domain models.",这几乎就是说域模型是在代码中定义的。
Eric Evans'DDD假设大多数软件开发中的复杂程度来自域,因此这种复杂域的模型对于管理复杂性至关重要。因此,当域复杂时,域建模是必需的。 DDD建议使用无处不在的域建模语言;也就是说,域专家和开发人员都很常见。这意味着至少在某些情况下,域模型不会用编程语言定义。有related question可能会有一些亮点(尽管它产生了大量的热量)。有些人批评这个问题的例子对于一个合理的领域模型来说太过琐碎(不够复杂)。
答案 2 :(得分:2)
“域模型”只是一个对象,它代表了您的业务领域中一些可辨别的概念。 “客户”,“订单”等。无论业务逻辑是什么,构成该逻辑的有形实体都是您域中的模型。
有些人会有很多业务逻辑(也许值得分解成其他类),有些人会很少(甚至没有)。
“域模型”和任何其他类之间的区别不是Java语言本身的构造,它主要是您定义的业务逻辑的语义构造。