tangyuxian
文章93
标签43
分类6

文章分类

文章归档

js-概念什么是领域模型

js-概念什么是领域模型

领域模型是对业务领域内概念、属性、行为和规则的抽象,它存在于 UI 视图层和底层数据(API/数据库)之间。

1. 核心定义 (High-Level Concept)

“领域模型(Domain Model)是解决业务问题的一组抽象概念。在前端开发中,它指的是不依赖于具体 UI 框架(如 React/Vue)的数据结构和业务逻辑层。”

它不是后端返回的 JSON 数据(那是 DTO),也不是 UI 的状态(View Model),而是业务本身的核心逻辑

2. 前端为什么需要领域模型? (The “Why”)

  • 逻辑复用与解耦 (Decoupling):
    • UI 组件应该只负责渲染。如果把“计算购物车总价”、“验证用户权限”等逻辑写在组件里,一旦 UI 改版或更换框架,这些逻辑很难复用。
    • 领域模型将这些逻辑封装在类(Class)或纯函数中,与 UI 彻底分离。
  • 应对接口变更 (Adapter Pattern):
    • 后端 API 经常变(字段名从 user_name 变成 username)。如果没有领域模型,你需要去修改几十个组件文件。
    • 如果有领域模型,你只需要在数据转换层(Adapter/ACL)修改一次映射关系即可。
  • 可测试性 (Testability):
    • 测试 UI 组件(Cypress/React Testing Library)通常很慢且脆弱。
    • 测试领域模型(纯 JS/TS 逻辑)非常快,可以直接编写单元测试验证业务规则。

3. 具体包含什么? (The Components)

在前端上下文中,领域模型通常包含以下几个部分(建议结合 TypeScript 回答):

  • 实体 (Entities): 具有唯一标识(ID)的对象。
    • 例子: User, Product, Order
  • 值对象 (Value Objects): 没有 ID,由属性描述的对象,通常是不可变的。
    • 例子: Address (包含省市区), Price (包含数值和货币单位), DateRange
  • 领域服务 (Domain Services): 处理涉及多个实体的复杂业务逻辑。
    • 例子: CartService.checkout(cart, user)

4. 代码举例 (Show Me The Code)

用一个对比例子最能说明问题。假设我们要展示一个用户的全名。

❌ 做法 A:贫血模型(逻辑散落在组件中)

后端返回 JSON,组件直接使用,逻辑写在 render 里。

1
2
3
4
5
6
7
8
// 组件内部
const UserProfile = ({ apiData }) => {
  // 业务逻辑混入 UI
  const fullName = `${apiData.first_name} ${apiData.last_name.toUpperCase()}`;
  const isVip = apiData.spent > 1000;

  return <div>{fullName} {isVip ? '(VIP)' : ''}</div>;
};

✅ 做法 B:充血领域模型(推荐)

定义一个 User 类(或带有方法的对象),封装逻辑。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// domain/User.ts
export class User {
  constructor(
    public id: string,
    public firstName: string,
    public lastName: string,
    private totalSpent: number
  ) {}

  // 业务逻辑内聚在模型中
  get fullName(): string {
    return `${this.firstName} ${this.lastName.toUpperCase()}`;
  }

  get isVip(): boolean {
    return this.totalSpent > 1000;
  }
}

// 转换层 (Adapter)
export function toUserDomain(dto: any): User {
  return new User(dto.id, dto.first_name, dto.last_name, dto.spent);
}

// 组件内部 - 变得非常干净
const UserProfile = ({ user }: { user: User }) => {
  return <div>{user.fullName} {user.isVip ? '(VIP)' : ''}</div>;
};

5. 领域模型 vs 其他概念 (Comparison)

它和 Vuex/Redux 或 DTO 的区别:

概念 说明 区别
DTO (Data Transfer Object) 后端 API 返回的原始 JSON 它是纯数据,没有行为(方法),且结构由后端决定。
Domain Model 业务实体 有数据也有行为,结构由前端业务需求决定。
View Model (Store/State) UI 状态 (Redux/Vuex) 包含 UI 特有的状态(如 isLoading, isModalOpen),通常引用 Domain Model。

6. 总结 (The Wrap-up)

总的来说,前端引入领域模型是为了让核心业务逻辑‘独立生存’。它让我们从‘写页面的’转变为‘设计软件的’。

在项目中,通常会在 API 层和组件层之间加一层 Model 层,利用 TypeScript 的 Class 来封装数据和行为,这样不仅让组件代码更简洁,也大大方便了单元测试和后续维护。

本文作者:tangyuxian
本文链接:https://www.tangyuxian.com/2025/12/18/qian-duan/javascript/js-gai-nian-shi-me-shi-ling-yu-mo-xing/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可
糖糖的AI分身(BETA)
如果加载时间过长,可尝试打开系统代理