第 17 章 Java 集合框架使用指南 Java集合框架使用指南
本作品已使用人工智能进行翻译。欢迎您提供反馈和意见:translation-feedback@oreilly.com
Java 集合框架自 1998 年首次出现以来,已被数百万工作中的 Java 程序员大量使用。本章的材料指出了我们可以从这些集体经验中汲取的一些教训。本章中的所有指导都是基于实际代码的经验,在实际代码中,如果不遵循这些指导,就会导致系统容易出错或难以维护。
在本章中,术语库、API 和客户端的含义如下:库是任何公开了公共方法的类,其API是其公开的公共方法的集合,客户端是任何调用 API 中方法的类。
备注
本章的代码示例可在以下网址找到:
https://github.com/MauriceNaftalin/JGC_2e_Book_Code/blob/main/src/main/java/org/jgcbook/chapter17
避免缺乏活力的领域模型
贫血领域模型(anemic domain model)一词是由 Martin Fowler(2003 年)提出的,用来描述的设计,在这种设计中,领域模型的对象基本上是数据载体,几乎不包含业务领域的逻辑。在面向对象设计的标准模型中,这会导致业务逻辑集中在服务层。Fowler 指出,"贫血领域模型的问题在于,它们会产生领域模型的所有成本(尤其是对持久性映射的需求),却不会产生任何好处"。他所描述的场景允许这些对象以领域空间中的名词命名,而在集合框架中,这种反模式表现为直接包含其他集合的无名集合结构,有时是深度嵌套的,并且不提供自定义行为。在两种情况下,对象设计失败的根本原因是相同的。
一个简单的例子就能说明问题。假设您决定在前几章的任务管理系统中引入一个新的实体:项目,它将任务集中在一个命名的标题下。为用户管理项目的服务层可以简单地将项目建模为从项目名称到任务集合的映射。服务层包括一个单一的示例方法--添加任务--大体上可以如下所示:
public class ServiceLayer {
Map<String,Set<Task>> projects = new HashMap<>();
public void addTask(String projectName, Task task) {
projects.merge(projectName, new HashSet<>(Set.of(task)),
(oldValue,newValue) -> {oldValue.addAll(newValue); return oldValue;});
}
...
}
在这里,贫血领域模型的核心问题显而易见:本应属于领域对象的逻辑并没有在这里得到表达,事实上,在这种表示法中,也无法在这里得到表达。因此,它必须由服务层来捕获。随着领域逻辑变得越来越复杂,这个问题也越来越严重。例如,假设任务的设计发生了变化,包含了持续时间:
public interface Task extends Comparable<Task> {
@Override
default int compareTo(Task t) {
return toString().compareTo(t.toString());
}
Duration duration();
}
Become an O’Reilly member and get unlimited access to this title plus top books and audiobooks from O’Reilly and nearly 200 top publishers, thousands of courses curated by job role, 150+ live events each month,
and much more.
Read now
Unlock full access