easy-model 领域驱动实践

18 阅读2分钟

在电商应用开发中,商品管理、购物车、订单处理等模块往往涉及复杂业务逻辑。easy-model 的模型驱动架构能有效组织这些领域知识,提升代码可维护性。本文通过实际用例展示如何使用 easy-model 实现电商领域的领域驱动开发。

商品管理模型

商品是电商的核心领域。我们可以创建一个 ProductModel 来封装商品状态和业务逻辑:

import { useModel } from "easy-model";

class ProductModel {
  product = {
    id: "",
    name: "",
    price: 0,
    stock: 0,
    category: ""
  };

  constructor(initialProduct: typeof this.product) {
    this.product = initialProduct;
  }

  updateStock(newStock: number) {
    if (newStock < 0) throw new Error("库存不能为负");
    this.product.stock = newStock;
  }

  isAvailable() {
    return this.product.stock > 0;
  }

  applyDiscount(discountPercent: number) {
    this.product.price *= (1 - discountPercent / 100);
  }
}

function ProductCard({ productId }: { productId: string }) {
  const productModel = useModel(ProductModel, [{
    id: productId,
    name: "iPhone 15",
    price: 5999,
    stock: 10,
    category: "电子产品"
  }]);

  return (
    <div>
      <h3>{productModel.product.name}</h3>
      <p>价格: ¥{productModel.product.price}</p>
      <p>库存: {productModel.product.stock}</p>
      <p>状态: {productModel.isAvailable() ? "有货" : "缺货"}</p>
      <button onClick={() => productModel.updateStock(productModel.product.stock - 1)}>
        购买
      </button>
    </div>
  );
}

这个模型封装了商品的业务规则,如库存管理、折扣应用等。领域逻辑集中,避免了在组件中散布业务代码。

购物车共享状态

电商应用中,购物车需要在多个组件间共享。easy-model 天然支持按用户分组的实例缓存:

import { useModel } from "easy-model";

class CartModel {
  items: Array<{ productId: string; quantity: number }> = [];
  userId: string;

  constructor(userId: string) {
    this.userId = userId;
  }

  addItem(productId: string, quantity: number) {
    const existing = this.items.find(item => item.productId === productId);
    if (existing) {
      existing.quantity += quantity;
    } else {
      this.items.push({ productId, quantity });
    }
  }

  getTotalItems() {
    return this.items.reduce((sum, item) => sum + item.quantity, 0);
  }
}

const CartProvider = provide(CartModel);

function CartIcon() {
  const cart = useModel(CartProvider, ["user123"]);
  return <div>购物车 ({cart.getTotalItems()})</div>;
}

function AddToCartButton({ productId }: { productId: string }) {
  const cart = useModel(CartProvider, ["user123"]);
  return (
    <button onClick={() => cart.addItem(productId, 1)}>
      加入购物车
    </button>
  );
}

通过 useModel,不同组件共享同一购物车实例,按用户ID分组,确保数据一致性。

订单异步处理

订单提交涉及异步操作。easy-model 的 @loader.load 装饰器简化加载状态管理:

import { loader, useLoader, useModel } from "easy-model";

class OrderModel {
  order = { id: "", status: "pending", items: [] };

  constructor(orderId: string) {
    this.order.id = orderId;
  }

  @loader.load(true)
  async submitOrder() {
    // 模拟API调用
    await new Promise(resolve => setTimeout(resolve, 2000));
    this.order.status = "confirmed";
  }
}

function OrderForm() {
  const orderModel = useModel(OrderModel, ["order123"]);
  const { isLoading } = useLoader();

  return (
    <div>
      <p>订单状态: {orderModel.order.status}</p>
      <button
        onClick={() => orderModel.submitOrder()}
        disabled={isLoading}
      >
        {isLoading ? "提交中..." : "提交订单"}
      </button>
    </div>
  );
}

useLoader 自动跟踪异步方法状态,无需手动管理 loading 布尔值。

测试驱动开发

easy-model 的模型类易于测试,确保业务逻辑正确:

import { describe, it, expect } from "vitest";

describe("ProductModel", () => {
  it("should update stock correctly", () => {
    const model = new ProductModel({
      id: "1",
      name: "Test",
      price: 100,
      stock: 5,
      category: "Test",
    });
    model.updateStock(3);
    expect(model.product.stock).toBe(3);
  });

  it("should throw on negative stock", () => {
    const model = new ProductModel({
      id: "1",
      name: "Test",
      price: 100,
      stock: 5,
      category: "Test",
    });
    expect(() => model.updateStock(-1)).toThrow();
  });
});

单元测试覆盖业务规则,提升代码质量。

总结

easy-model 在电商应用中展现出强大实力:模型封装领域逻辑、provide 支持状态共享、@loader.load 简化异步处理。结合 Vitest 测试,确保高质量交付。试试 easy-model,让电商开发更优雅!

项目地址:GitHub