为什么DDD不是“另一种模式”
\n\n您是否曾经因为“业务逻辑分散在所有控制器中”而从头重写项目?或者,您的UserManager是否膨胀到2000行,没有人真正理解它在做什么?听起来熟悉吗?
在Swift开发的世界里,我们已经习惯了MVC、VIPER或MVVM。但所有这些模式都解决同一个问题:如何将UI与逻辑分离。然而,它们几乎没告诉我们如何组织业务逻辑本身。这时,领域驱动设计(DDD)登场了——这是一种将应用程序的领域置于核心,而非框架的方法。
\n\n在本文中,我们将通过实际示例探讨如何在Swift中应用领域驱动设计。您将看到,DDD并非抽象理论,而是一个强大的工具,能使代码可读、可测试且易于应对变化。
\n\n用简单的话说什么是DDD
\n\n想象一下,您正在编写一个电商应用。MVC会告诉您:“创建一个Product模型、一个ProductViewController控制器和视图。”而DDD会问:“在您的业务中,‘商品’是什么?它可以没有价格吗?当它被添加到购物车时会发生什么?”
领域驱动设计是一种软件建模方式,使代码尽可能精确地反映业务的语言和规则。您不再使用“技术性”实体(如DataManager),而是使用领域对象:Order、Customer、Invoice。
DDD的基本构建块
\n\n为了避免在术语中迷失,请记住三个主要概念:
\n\n- \n
- Entity(实体)——具有身份的对象。两个字段相同的对象是不同的实体(就像两个同名不同人)。 \n
- Value Object(值对象)——仅由其属性定义的对象。如果两个对象的所有字段都匹配,它们就是同一个对象(如日期或金额)。 \n
- Aggregate(聚合)——一组被视为一个整体的相关对象。聚合有一个根(root entity),通过它可以访问所有内部对象。 \n
听起来很枯燥?让我们用Swift来实现。
\n\n用Swift编写领域模型
\n\n假设我们正在构建一个任务管理应用(TODO列表)。我们从最简单的开始——任务状态的Value Object。
\n\n// Value Object: 任务状态\nstruct TaskStatus: Equatable {\n let rawValue: String\n \n static let todo = TaskStatus(rawValue: "todo")\n static let inProgress = TaskStatus(rawValue: "inProgress")\n static let done = TaskStatus(rawValue: "done")\n \n // 业务规则:只能转换到下一个状态\n func canTransition(to newStatus: TaskStatus) -> Bool {\n switch (self, newStatus) {\n case (.todo, .inProgress), (.inProgress, .done):\n return true\n default:\n return false\n }\n }\n}\n\n请注意:我们没有使用枚举,因为在真实业务中,状态可能来自服务器或存储在数据库中。TaskStatus是一个不可变对象,它自身知道自己的规则。
现在,我们创建一个Entity——任务本身:
\n\n// Entity: 任务\nfinal class Task {\n let id: UUID\n var title: String\n var description: String\n private(set) var status: TaskStatus\n let createdAt: Date\n \n init(id: UUID = UUID(), title: String, description: String, status: TaskStatus = .todo) {\n self.id = id\n self.title = title\n self.description = description\n self.status = status\n