在 Laravel 中 DDD 与 MVC 协同工作全解析

DDD 与 MVC 协同工作全解析

在 Laravel 项目中,DDD(领域驱动设计)和 MVC(模型-视图-控制器)可以协同工作,形成一种分层架构。DDD 提供了更高级的业务抽象,而 MVC 作为展示层的实现方式。下面我将详细解释二者如何协同工作:

协同架构示意图

          [用户界面]
               │
               ▼
┌───────────────────────────────┐
│           MVC 层             │
│ ┌────────────┬──────────────┐ │
│ │ 控制器     │ 视图         │ │
│ │ (Controller)│ (Views)     │ │
│ └────────────┴──────────────┘ │
└──────────────┬────────────────┘
               │
               ▼
┌───────────────────────────────┐
│         DDD 应用层           │
│ ┌────────────────────────────┐│
│ │ 应用服务                   ││
│ │ (Application Services)     ││
│ └────────────────────────────┘│
└──────────────┬────────────────┘
               │
               ▼
┌───────────────────────────────┐
│         DDD 领域层           │
│ ┌──────┬────────┬───────────┐│
│ │ 实体 │ 值对象 │ 领域服务   ││
│ │      │        │ 聚合根     ││
│ └──────┴────────┴───────────┘│
└──────────────┬────────────────┘
               │
               ▼
┌───────────────────────────────┐
│       DDD 基础设施层          │
│ ┌────────────┬──────────────┐ │
│ │ 仓储实现   │ 外部服务适配器│ │
│ │ (数据库/API)              │ │
│ └────────────┴──────────────┘ │
└───────────────────────────────┘

协同工作流程

  1. 请求进入 MVC 控制器

    • 控制器处理 HTTP 请求
    • 验证输入数据
    • 准备调用应用层服务
  2. 调用 DDD 应用层

    • 控制器调用应用服务
    • 应用服务协调领域对象
    • 应用服务处理事务边界
  3. 领域层执行业务逻辑

    • 应用服务调用领域实体、值对象
    • 业务规则在领域层执行
    • 领域事件在此触发
  4. 基础设施层提供支持

    • 领域层通过接口访问仓储
    • 基础设施层实现具体持久化
    • 外部服务通过适配器集成
  5. 结果返回 MVC 层

    • 应用服务返回结果
    • 控制器准备响应
    • 视图渲染返回给用户

Laravel 中的协同实现

项目结构

app/
├── Http/                     # MVC 层 (展示层)
│   ├── Controllers/          # 控制器
│   ├── Requests/             # 表单请求
│   └── Resources/            # API 资源
│
├── Application/              # DDD 应用层
│   ├── Services/             # 应用服务
│   └── DTOs/                 # 数据传输对象
│
├── Domain/                   # DDD 领域层
│   ├── Order/                # 订单子域
│   │   ├── Models/           # 实体
│   │   ├── ValueObjects/     # 值对象
│   │   ├── Repositories/     # 仓储接口
│   │   ├── Services/         # 领域服务
│   │   └── Events/           # 领域事件
│   └── User/                 # 用户子域
│
└── Infrastructure/           # DDD 基础设施层
    ├── Repositories/         # 仓储实现
    ├── Providers/            # 服务提供者
    └── Listeners/            # 事件监听器

代码示例

1. MVC 控制器(展示层)
namespace App\Http\Controllers;

use App\Application\Services\OrderService;
use App\Http\Requests\CreateOrderRequest;
use App\Http\Resources\OrderResource;

class OrderController extends Controller
{
    public function __construct(private OrderService $orderService) 
    {
    }

    public function store(CreateOrderRequest $request)
    {
        // 调用应用服务处理业务逻辑
        $order = $this->orderService->createOrder(
            $request->validated()['items'],
            $request->user()->id
        );
        
        // 返回格式化响应
        return new OrderResource($order);
    }
}
2. DDD 应用服务(应用层)
namespace App\Application\Services;

use App\Domain\Order\Models\Order;
use App\Domain\Order\Repositories\OrderRepositoryInterface;
use App\Domain\Order\Services\OrderCalculationService;

class OrderService
{
    public function __construct(
        private OrderRepositoryInterface $orderRepository,
        private OrderCalculationService $calculationService
    ) {
    }

    public function createOrder(array $items, int $userId): Order
    {
        // 创建订单实体
        $order = new Order($userId);
        
        // 添加订单项(领域行为)
        foreach ($items as $item) {
            $order->addItem($item['product_id'], $item['quantity']);
        }
        
        // 计算订单总额(领域服务)
        $order->setTotal($this->calculationService->calculateTotal($order));
        
        // 保存订单
        $this->orderRepository->save($order);
        
        // 返回领域实体
        return $order;
    }
}
3. DDD 领域模型(领域层)
namespace App\Domain\Order\Models;

class Order
{
    private array $items = [];
    private float $total = 0.0;
    
    public function __construct(
        private int $userId,
        private OrderStatus $status = OrderStatus::PENDING
    ) {
    }
    
    // 领域行为:添加订单项
    public function addItem(int $productId, int $quantity): void
    {
        if ($quantity <= 0) {
            throw new \InvalidArgumentException('Quantity must be positive');
        }
        
        $this->items[] = new OrderItem($productId, $quantity);
    }
    
    // 设置总额(由领域服务计算)
    public function setTotal(float $total): void
    {
        $this->total = $total;
    }
    
    // 完成订单业务逻辑
    public function complete(): void
    {
        if ($this->status !== OrderStatus::PAID) {
            throw new \DomainException('Only paid orders can be completed');
        }
        
        $this->status = OrderStatus::COMPLETED;
        $this->recordEvent(new OrderCompleted($this->id));
    }
}
4. 基础设施层实现
namespace App\Infrastructure\Repositories\Eloquent;

use App\Domain\Order\Models\Order as OrderEntity;
use App\Domain\Order\Repositories\OrderRepositoryInterface;
use App\Models\Order as OrderModel; // Eloquent 模型

class OrderRepository implements OrderRepositoryInterface
{
    public function save(OrderEntity $order): void
    {
        $model = OrderModel::updateOrCreate(
            ['id' => $order->getId()],
            [
                'user_id' => $order->getUserId(),
                'total' => $order->getTotal(),
                'status' => $order->getStatus()->value,
            ]
        );
        
        if (!$order->getId()) {
            $order->setId($model->id);
        }
    }
}

数据流转换视图

HTTP 请求 
→ MVC 控制器 (接收并验证)
→ 应用服务 (协调流程)
→ 领域实体 (执行业务规则)
→ 仓储接口 
→ 仓储实现 (Eloquent/数据库)
→ 返回领域实体
→ 应用服务 
→ MVC 控制器 
→ HTTP 响应 (JSON/视图)

最佳实践与注意事项

  1. 明确层边界

    • 控制器应简单,只负责 HTTP 交互
    • 业务逻辑应位于领域层
    • 持久化细节在基础设施层实现
  2. 依赖方向

    控制器
    应用服务
    领域模型
    仓储接口
    基础设施实现

    依赖应指向内层(领域层),外层依赖内层

  3. 贫血模型 vs 充血模型

    • MVC 中的模型通常是贫血的数据容器
    • DDD 中的实体是包含行为的充血模型
  4. 何时使用哪种模式

    • 简单 CRUD:优先使用 MVC
    • 复杂业务逻辑:引入 DDD 概念
    • 核心子域:实施完整 DDD
  5. 渐进式采用

    timeline
      初始阶段 : MVC + 服务层
      演进阶段 : 提取领域模型
      成熟阶段 : 完整 DDD 分层
    
  6. 测试策略

    • 控制器:测试 HTTP 响应
    • 应用服务:测试用例流程
    • 领域模型:单元测试业务规则
    • 基础设施:集成测试

常见陷阱与解决方案

  1. 控制器膨胀
    问题:业务逻辑泄漏到控制器
    解决方案:立即委托给应用服务

  2. 领域模型依赖框架
    问题:在领域实体中使用 Eloquent
    解决方案:严格分离,使用数据映射器

  3. 过度设计
    问题:简单 CRUD 实施完整 DDD
    解决方案:只在复杂领域使用完整 DDD

  4. 层间数据传输
    问题:直接传递 Eloquent 模型
    解决方案:使用 DTO 或领域实体作为边界对象

总结

DDD 与 MVC 在 Laravel 中可以完美协同:

  • MVC 负责展现层:处理 HTTP 请求/响应、视图渲染
  • DDD 负责业务层:建模复杂业务逻辑、维护核心领域

通过分层架构:

  1. 上层(MVC)依赖于下层(DDD)
  2. 领域层保持技术无关性
  3. 基础设施层提供具体实现

这种协同模式允许团队:

  • 对复杂核心业务使用 DDD 的严谨建模
  • 对简单辅助功能使用 MVC 的高效开发
  • 根据需要灵活组合两种模式

最终得到一个既能在核心业务保持领域完整性,又能在其他部分保持开发效率的系统架构。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值