Files
DDDMicroFrontend/doc/杂项.md
2025-09-16 22:08:45 +08:00

3.1 KiB
Raw Blame History

横切关注点

  • 特征:横向,影响多个模块,那些无法放入任何一个业务模块,而是会"横着"贯穿多个甚至所有模块的技术性需求。
  • 案例:日志记录、身份认证、授权、事务管理、异常处理、缓存、性能监控

业务关注点

  • 特征:通常局限于一个业务模块内
  • 案例:计算订单总额、验证用户邮箱格式、处理库存扣减

对象职责的设计理念对比:

贫血模型

  • 特征:对象仅仅是数据的容器(一堆属性的集合),没有任何业务逻辑。所有操作这些数据的逻辑都放在外部的“服务”或“工具”类中。
  • 比喻:像一个没有灵魂的空壳,或者一个数据结构。它只负责装数据,至于数据怎么用、怎么变,它不管。
// 1. 贫血的Order实体只有数据没有行为
class Order {
  public id: string;
  public items: OrderItem[];
  public total: number; // 总额需要外部来计算和设置
  public status: string;
}

// 2. 所有业务逻辑都在外部的“服务”里
class OrderService {
  calculateTotal(order: Order): void {
    let total = 0;
    for (const item of order.items) {
      total += item.price * item.quantity;
    }
    order.total = total; // 从外部修改对象的数据
  }

  markAsPaid(order: Order): void {
    if (order.total <= 0) {
      throw new Error('订单金额无效');
    }
    order.status = 'paid'; // 从外部修改对象的状态
  }
}

// 使用方式
const order = new Order();
order.items = [...];
const orderService = new OrderService();
orderService.calculateTotal(order); // 服务来算总额
orderService.markAsPaid(order); // 服务来改状态

充血模型

  • 特征:对象不仅包含数据,还包含与这些数据紧密相关的业务逻辑。它是有行为和责任的。
  • 比喻:像一个有智慧的专家。它不仅拥有数据,还知道如何操作和处理自己的数据。
// 充血的Order实体数据 + 行为
class Order {
  public id: string;
  private _items: OrderItem[];
  private _total: number; // 总额是内部计算的结果
  public status: string;

  constructor(items: OrderItem[]) {
    this._items = items;
    this._total = this.calculateTotal(); // 构造时自己计算总额
    this.status = 'created';
  }

  // 业务逻辑封装在实体内部
  private calculateTotal(): number {
    return this._items.reduce((sum, item) => sum + (item.price * item.quantity), 0);
  }

  // 一个公开的业务方法
  public markAsPaid(): void {
    // 它自己 knows 自己的业务规则
    if (this._total <= 0) {
      throw new Error('订单金额无效,无法支付');
    }
    this.status = 'paid';
  }

  // 提供访问内部数据的方法(如果需要)
  get total(): number {
    return this._total;
  }

  get items(): ReadonlyArray<OrderItem> {
    return [...this._items]; // 返回副本,保护内部数据
  }
}

// 使用方式:对象是聪明的,告诉它做什么就行,而不是一步步操作它
const order = new Order([...]);
order.markAsPaid(); // 对象自己处理状态变更