项目开发笔记-1

MVC,DDD与各类术语

Posted by Sirin on October 29, 2025

MVC

MVC是一种软件设计模式,即模型-视图-控制器(Model-View-Controller)

模型 Model

代表了应用程序的核心数据和业务逻辑,包括数据的存取、验证和处理,业务规则的执行。

它不关心用户界面;只接受控制器的指令,不会直接处理用户输入;状态发生变化时,会通知相关的视图进行更新。

视图 View

视图负责将模型中的数据呈现给用户,是用户的交互界面,负责数据的展示和接收用户的输入。

视图本身不包含任何业务逻辑,只负责显示控制器传输给它的数据;一个模型可以对应于多个视图,模型更新时,视图会相应更新。

控制器 Controller

控制器作为模型和视图之间的协调者,负责接收用户请求、调用相应的模型、选择相应的视图。

本身并不包含业务逻辑,只负责调用包含了相应业务逻辑的模型;不关心数据的显示,只负责将处理后的数据传递给相应的视图。


DDD简介

DDD即领域驱动设计(Domain-Driven Design)

其核心理念包括

  • 领域模型(Domain Model):DDD的核心,对特定业务领域知识的精确表述,用代码来反映了业务的核心概念、规则和逻辑。
  • 统一语言(Ubiquitous Language):开发团队和业务专家共用的语言,用于确保所有人对业务概念有着相同的理解。
  • 限界上下文(Bounded Context):如果没有限界上下文,我们可能会试图创建一个包含所有属性和行为的“大而全”的产品类,这将导致类过于复杂,且不同场景下的焦点内容相互干扰。因此,限界上下文就是将这些不同场景下的模型分开,每个上下文有自己独立的模型,并明确边界。这样,每个上下文内的模型可以保持内聚,而不受其他上下文的影响。
  • 聚合(Aggregate):聚合是一组相关对象的集合,被视为数据修改的单元,每个聚合都有一个聚合根(外部对象与聚合内部对象交互的唯一入口)。
  • 领域服务(Domain Services):当一些操作不自然属于任何实体或者值对象(例如转账服务、商品推荐服务)的时候,它们被定义为领域服务,表示领域中的一些操作或者业务逻辑,专注于业务规则(做什么)。
  • 应用服务(Application Services):用于协调流程,不包含业务逻辑,关注如何通过协调多个领域服务和基础设施来完成用户任务。
  • 基础设施(Infrastructure):为领域模型提供持久化机制(数据库)、消息传递、应用程序的配置等技术组件。
  • 领域事件(Domain Events):领域中发生的有意义的业务事件,可以触发其他子系统的反应或流程。

对于领域模型,其下包括三个主要组件:领域对象,领域服务,仓储服务

实体,聚合,值对象位于领域下的领域对象内,服务于领域内的领域服务。

实体

实体 = 唯一标识 + 状态属性 + 行为动作

实体是DDD中的一个基本构件块,代表了具有唯一标识的实体对象,包含了数据和行为,且它的标识在整个生命周期中保持不变。

值对象

值对象 = 值 + 对象

值对象由一组属性构成,与实体不同,值对象不需要一个唯一标识符来区别。值对象是不可变的,创建后,其状态不应再改变。

值对象的等价性依赖于对象的属性值,如果两个值对象的所有属性值都相等,则可以认为两个对象是等价的。且由于值对象的不可变性,任何改变值对象的操作,都会变成重新创建一个新的值对象实例,而不是修改现有的实例。

值对象侧重于表示事物的状态,而非其唯一身份。其用途例如 金额和货币(价格 工资)、度量和数据(重量 长度 体积)、范围和区间(日期范围 温度区间) 复杂的数学模型(向量 坐标) 等。

聚合

聚合是一组具有内聚性的相关对象的集合,这些对象一起工作以执行某些业务规则或操作。聚合定义了一组对象的边界,这些对象可以被视为一个单元进行处理。

聚合确保了其内部对象的状态变化是一致的,对聚合内对象进行操作时,必须保持聚合内对象的一致性;每个聚合都有一个聚合根,它具有全局唯一的标识符,是外部和聚合交互的入口;聚合定义了事务的边界,聚合内部的变更操作是原子的(要么全部失败,要么全部成功),从而保证数据的一致性。

仓储(Repository)与适配器(Adapter)

传统的Services + 数据模型的设计,会在Services中引入Redis、RPC等其他外部服务,造成技术细节和业务逻辑混杂污染,一旦要修改外部数据库,就需要重构所有项目中关于数据模型的代码。

DDD中通过仓储、适配器和基础设施层的定义,将这一部分解耦,起到了防腐层的作用。

Repository

对于仓储服务,其特征包括:

  • 封装持久化操作:仓储封装了所有与数据源交互的操作,例如创建、读取、更新、删除(CRUD)操作,领域层只需关注业务逻辑,无需在意数据库或其他存储机制的复杂性。
  • 领域对象集合管理:仓储可以看作是领域对象的集合,提供了查询、过滤这些领域对象的方法,简化了领域对象的获取和管理。
  • 抽象接口:仓储定义的接口与持久化机制无关,使得领域层的代码可以在不同的持久化机制(e.g., MySQL & MongoDB)之间切换而无需修改。

Adapter

适配器的交互对象则是第三方API、消息队列和外部服务等,在DDD中,适配器通常和端口组合形成 Ports and Adapters架构,也被称为六边形架构。端口在这种架构中代表了应用程序的一个出口/入口,定义了一个与外部世界交互的接口,但不关心具体的实现细节。其实现涉及到:

  1. 在领域层定义清晰的端口,代表了应用程序与外部世界的交互点
  2. 在应用层或者基础设施层实现Adapters,这些适配器负责将端口的抽象操作转化为具体的外部调用
  3. 采用依赖倒置,应用程序的核心逻辑依赖于抽象的端口接口,而不是具体的适配器实现,因此适配器可以随时替换(防腐设计)
  4. 应用程序启动时,只需要将适配器与相应的端口连接。

DDD层级关系

主要的三层结构是

  • 领域层:关注业务逻辑的实现,包括实体、值对象中的方法,领域服务中的复杂业务操作,业务规则验证、计算和状态转化。
  • 应用层:关注业务逻辑的协调,组合多个领域对象的操作,管理事务边界和安全控制,调用外部服务,发布集成事件。
  • 基础设施层:关注技术实现,包括数据持久化,消息发送,API调用。本身不包含任何业务逻辑。

下面我们详细介绍一下领域层。

关于领域(Domain)

领域,是指具体的业务领域的知识、业务逻辑、业务规则和数据的集合,领域通常由一系列子领域组成,每个子领域代表了业务中的一个特定部分。

领域的特性包括:

  • 业务中心:领域是围绕业务需求和业务规则来构建的,是软件设计的核心。
  • 模型驱动:领域模型是对业务知识的抽象,通过实体、值对象、聚合和服务来表达。
  • 语言一致性:领域模型的构建基于统一语言,确保开发团队和业务专家沟通无歧义。
  • 边界清晰:领域模型定义了清晰的边界,划分了不同的子领域和聚合。
  领域 领域对象
本质存在 客观存在的业务现实 主观设计的抽象表达
关注点 业务规则,流程,术语 类设计、对象协作、代码实现
参与设计者 业务专家 开发团队
  业务是什么 如何理解和表达业务