【系统设计】大神三分钟搞懂领域驱动设计(三)

简介: 【系统设计】大神三分钟搞懂领域驱动设计

入门

正如我在开始时所说,你可能在DDD之前遇到过很多想法。事实上,我所说过的每一个Smalltalker(我不是一个,我不敢说)似乎很高兴能够在EJB2等人的荒野岁月之后回归域驱动的方法。

另一方面,如果这些东西是新的怎么办?有这么多不同的方式来绊倒,有没有办法可靠地开始使用DDD?

如果你环顾一下Java领域(对.NET来说并不那么糟糕),实际上有数百个用于构建Web应用程序的框架(JSP,Struts,JSF,Spring MVC,Seam,Wicket,Tapestry等)。从持久性角度(JDO,JPA,Hibernate,iBatis,TopLink,JCloud等)或其他问题(RestEasy,Camel,ServiceMix,Mule等),有很多针对基础架构层的框架。但是很少有框架或工具来帮助DDD所说的最重要的层,即域层。

自2002年以来,我一直参与(现在是一个提交者)一个名为Naked Objects的项目,Java上的开源[12]和.NET上的商业[13]。虽然Naked Objects没有明确地开始考虑领域驱动的设计 - 事实上它早于Evans的书 - 它与DDD的原理非常相似。它还可以轻松克服前面提到的障碍。

您可以将Naked Objects视为与Hibernate等ORM类似。 ORM构建域对象的元模型并使用它来自动将域对象持久保存到RDBMS,而Naked Objects构建元模型并使用它在面向对象的用户界面中自动呈现这些域对象。

开箱即用的Naked Objects支持两个用户界面,一个富客户端查看器(参见图9)和一个HTML查看器(参见图10)。这些都是功能完备的应用程序,需要开发人员只编写要运行的域层(实体,值,存储库,工厂,服务)。

Figure 9: Naked Objects Drag-n-Drop Viewer


我们来看看Claim类的(Java)代码(如屏幕截图所示)。首先,这些类基本上是pojos,尽管我们通常从便捷类AbstractDomainObject继承,只是为了分解注入通用存储库并提供一些帮助方法:

public class Claim extends AbstractDomainObject {
...
}
Next, we have some value properties:
// {{ Description
private String description;
@MemberOrder(sequence = "1")
public String getDescription() { return description; }
public void setDescription(String d) { description = d; }
// }}
// {{ Date
private Date date;
@MemberOrder(sequence="2")
public Date getDate() { return date; }
public void setDate(Date d) { date = d; }
// }}
// {{ Status
private String status;
@Disabled
@MemberOrder(sequence = "3")
public String getStatus() { return status; }
public void setStatus(String s) { status = s; }
// }}

这些是简单的getter / setter,返回类型为String,日期,整数等(尽管Naked Objects也支持自定义值类型)。接下来,我们有一些参考属性:

// {{ Claimant
private Claimant claimant;
@Disabled
@MemberOrder(sequence = "4")
public Claimant getClaimant() { return claimant; }
public void setClaimant(Claimant c) { claimant = c; }
// }}
// {{ Approver
private Approver approver;
@Disabled
@MemberOrder(sequence = "5")
public Approver getApprover() { return approver; }
public void setApprover(Approver a) { approver = a; }
// }}

这里我们的Claim实体引用其他实体。实际上,Claimant和Approver是接口,因此这允许我们将域模型分解为模块,如前所述。

实体也可以拥有实体集合。在我们的案例中,Claim有一个ClaimItems的集合:

// {{ Items
private List<ClaimItem> items = new
ArrayList<ClaimItem>();
@MemberOrder(sequence = "6")
public List<ClaimItem> getItems() { return items; }
public void addToItems(ClaimItem item) {
items.add(item);
}
// }}

我们还有(Naked Objects调用的)动作,即submit和addItem:这些都是不代表属性和集合的公共方法:

// {{ action: addItem
public void addItem(
@Named("Days since")
int days,
@Named("Amount")
double amount,
@Named("Description")
String description) {
ClaimItem claimItem = newTransientInstance(ClaimItem.class);
Date date = new Date();
date = date.add(0,0, days);
claimItem.setDateIncurred(date);
claimItem.setDescription(description);
claimItem.setAmount(new Money(amount, "USD"));
persist(claimItem);
addToItems(claimItem);
}
public String disableAddItem() {
return "Submitted".equals(getStatus()) ? "Already
submitted" : null;
}
// }}
// {{ action: Submit
public void submit(Approver approver) {
setStatus("Submitted");
setApprover(approver);
}
public String disableSubmit() {
return getStatus().equals("New")?
null : "Claim has already been submitted";
}
public Object[] defaultSubmit() {
return new Object[] { getClaimant().getApprover() };
}
// }}

这些操作会在Naked Objects查看器中自动呈现为菜单项或链接。而这些行动的存在意味着Naked Objects应用程序不仅仅是CRUD风格的应用程序。

最后,有一些支持方法可以显示标签(或标题)并挂钩持久性生命周期:

// {{ Title
public String title() {
return getStatus() + " - " + getDate();
}
// }}
// {{ Lifecycle
public void created() {
status = "New";
date = new Date();
}
// }}

之前我将Naked Objects域对象描述为pojos,但您会注意到我们使用注释(例如@Disabled)以及命令式帮助器方法(例如disableSubmit())来强制执行业务约束。 Naked Objects查看器通过查询启动时构建的元模型来尊重这些语义。如果您不喜欢这些编程约定,则可以更改它们。

典型的Naked Objects应用程序由一组域类组成,例如上面的Claim类,以及存储库,工厂和域/基础结构服务的接口和实现。特别是,没有表示层或应用层代码。那么Naked Objects如何帮助解决我们已经确定的一些障碍?

  • 实施分层架构:因为我们编写的唯一代码是域对象,域逻辑无法渗透到其他层。实际上,Naked Objects最初的动机之一就是帮助开发行为完整的对象
  • 表示层模糊了域层:因为表示层是域对象的直接反映,整个团队可以迅速加深对域模型的理解。默认情况下,Naked Objects直接从代码中获取类名和方法名,因此强烈要求在无处不在的语言中获得命名权。通过这种方式,Naked Objects也支持DDD的模型驱动设计原理
  • 存储库模式的实现:您可以在屏幕截图中看到的图标/链接实际上是存储库:EmployeeRepository和ClaimRepository。 Naked Objects支持可插入对象存储,通常在原型设计中,我们使用针对内存中对象存储的实现。当我们转向生产时,我们会编写一个实现数据库的实现。
  • 服务依赖项的实现:Naked Objects会自动将服务依赖项注入每个域对象。这是在从对象库中检索对象时,或者首次创建对象时完成的(请参阅上面的newTransientInstance())。事实上,这些辅助方法所做的就是委托Naked Objects提供的名为DomainObjectContainer的通用存储库/工厂。
  • 不合适的模块化:我们可以通过正常方式使用Java包(或.NET命名空间)模块化为模块,并使用Structure101 [14]和NDepend [15]等可视化工具来确保我们的代码库中没有循环依赖。我们可以通过注释@Hidden来模块化为聚合,任何聚合对象代表我们可见聚合根的内部工作;这些将不会出现在Naked Objects查看器中。我们可以编写域和基础设施服务,以便根据需要桥接到其他BC。
  • Naked Objects提供了许多其他功能:它具有可扩展的体系结构 - 特别是 - 允许实现其他查看器和对象存储。正在开发的下一代观众(例如Scimpi [16])提供更复杂的定制功能。此外,它还提供多种部署选项:例如,您可以使用Naked Objects进行原型设计,然后在进行生产时开发自己的定制表示层。它还与FitNesse [17]等工具集成,可以自动为域对象提供RESTful接口[18]。

下一步

领域驱动的设计汇集了一组用于开发复杂企业应用程序的最佳实践模式。一些开发人员多年来一直在应用这些模式,对于这些人来说,DDD可能只是对他们现有实践的肯定。但对于其他人来说,应用这些模式可能是一个真正的挑战。

Naked Objects为Java和.NET提供了一个框架,通过处理其他层,团队可以专注于重要的部分,即域模型。通过直接在UI中公开域对象,Naked Objects允许团队非常自然地构建一个明确无处不在的语言。随着域层的建立,团队可以根据需要开发更加量身定制的表示层。

那么,下一步呢?

嗯,DDD本身的圣经是埃里克埃文斯的原着,“领域驱动设计”[1],建议阅读所有人。雅虎新闻组DDD [19]也是一个非常好的资源。如果你有兴趣了解Naked Objects的更多信息,你可以搜索我的书“使用Naked Objects的域驱动设计”[20],或者我的博客[21](NO for Java)或Naked Objects网站[13 ](对于.NET而言)。快乐DDD'ing!

References

Related Methods & Tools articles

  • Domain-Specific Modeling for Full Code Generation
  • Mass Customizing Solutions with Software Factories
  • Introduction to the Emerging Practice of Software Product Line Development

More Domain Driven Design Knowledge

  • Strategic Design by Eric Evans
  • Is Domain-Driven Design more than Entities and Repositories?
  • Use of Domain Driven Design in Enterprise Application Development
相关文章
|
监控 前端开发 测试技术
吃透这些软件测试理论知识要点,你就搞懂了软件测试
吃透这些软件测试理论知识要点,你就搞懂了软件测试
380 0
|
2月前
|
设计模式 架构师 Java
一文详谈领域驱动设计实践
本文作者结合在团队的实践过程,分享了自己对领域驱动设计的一些思考。
180 8
|
8月前
|
设计模式 开发者
第一篇 设计模式引论 - 探索软件设计的智慧结晶
第一篇 设计模式引论 - 探索软件设计的智慧结晶
|
8月前
|
设计模式 存储 算法
【软件设计师—基础精讲笔记7】第七章 面向对象技术
【软件设计师—基础精讲笔记7】第七章 面向对象技术
140 1
|
存储 开发框架 Java
【领域驱动设计】三分钟搞懂领域驱动设计(一)
【领域驱动设计】三分钟搞懂领域驱动设计
|
存储 开发框架 Java
【领域驱动设计】大神三分钟搞懂领域驱动设计(上)
【领域驱动设计】大神三分钟搞懂领域驱动设计
|
前端开发 Java 程序员
【系统设计】大神三分钟搞懂领域驱动设计(一)
【系统设计】大神三分钟搞懂领域驱动设计
【系统设计】大神三分钟搞懂领域驱动设计(一)
|
存储 前端开发 数据可视化
【领域驱动设计】三分钟搞懂领域驱动设计(二)
【领域驱动设计】三分钟搞懂领域驱动设计
|
存储 开发框架 Java
【领域驱动设计】三分钟搞懂领域驱动设计(上)
【领域驱动设计】三分钟搞懂领域驱动设计
|
存储 前端开发 数据可视化
【领域驱动设计】三分钟搞懂领域驱动设计(下)
【领域驱动设计】三分钟搞懂领域驱动设计

热门文章

最新文章