在 Laravel 中 DDD 与 MVC 协同工作全解析
DDD与MVC在Laravel中的协作架构解析:MVC作为展示层处理HTTP请求和响应,DDD则分层实现业务逻辑。MVC控制器调用DDD应用服务,应用层协调领域对象执行业务规则,基础设施层提供持久化支持。项目结构清晰划分:Http/为MVC层,Application/为应用服务,Domain/包含领域模型,Infrastructure/实现仓储等基础设施。这种分层架构既保持了MVC的简洁性,又实现
·
DDD 与 MVC 协同工作全解析
在 Laravel 项目中,DDD(领域驱动设计)和 MVC(模型-视图-控制器)可以协同工作,形成一种分层架构。DDD 提供了更高级的业务抽象,而 MVC 作为展示层的实现方式。下面我将详细解释二者如何协同工作:
协同架构示意图
[用户界面]
│
▼
┌───────────────────────────────┐
│ MVC 层 │
│ ┌────────────┬──────────────┐ │
│ │ 控制器 │ 视图 │ │
│ │ (Controller)│ (Views) │ │
│ └────────────┴──────────────┘ │
└──────────────┬────────────────┘
│
▼
┌───────────────────────────────┐
│ DDD 应用层 │
│ ┌────────────────────────────┐│
│ │ 应用服务 ││
│ │ (Application Services) ││
│ └────────────────────────────┘│
└──────────────┬────────────────┘
│
▼
┌───────────────────────────────┐
│ DDD 领域层 │
│ ┌──────┬────────┬───────────┐│
│ │ 实体 │ 值对象 │ 领域服务 ││
│ │ │ │ 聚合根 ││
│ └──────┴────────┴───────────┘│
└──────────────┬────────────────┘
│
▼
┌───────────────────────────────┐
│ DDD 基础设施层 │
│ ┌────────────┬──────────────┐ │
│ │ 仓储实现 │ 外部服务适配器│ │
│ │ (数据库/API) │ │
│ └────────────┴──────────────┘ │
└───────────────────────────────┘
协同工作流程
-
请求进入 MVC 控制器
- 控制器处理 HTTP 请求
- 验证输入数据
- 准备调用应用层服务
-
调用 DDD 应用层
- 控制器调用应用服务
- 应用服务协调领域对象
- 应用服务处理事务边界
-
领域层执行业务逻辑
- 应用服务调用领域实体、值对象
- 业务规则在领域层执行
- 领域事件在此触发
-
基础设施层提供支持
- 领域层通过接口访问仓储
- 基础设施层实现具体持久化
- 外部服务通过适配器集成
-
结果返回 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/视图)
最佳实践与注意事项
-
明确层边界:
- 控制器应简单,只负责 HTTP 交互
- 业务逻辑应位于领域层
- 持久化细节在基础设施层实现
-
依赖方向:
依赖应指向内层(领域层),外层依赖内层
-
贫血模型 vs 充血模型:
- MVC 中的模型通常是贫血的数据容器
- DDD 中的实体是包含行为的充血模型
-
何时使用哪种模式:
- 简单 CRUD:优先使用 MVC
- 复杂业务逻辑:引入 DDD 概念
- 核心子域:实施完整 DDD
-
渐进式采用:
timeline 初始阶段 : MVC + 服务层 演进阶段 : 提取领域模型 成熟阶段 : 完整 DDD 分层
-
测试策略:
- 控制器:测试 HTTP 响应
- 应用服务:测试用例流程
- 领域模型:单元测试业务规则
- 基础设施:集成测试
常见陷阱与解决方案
-
控制器膨胀:
问题:业务逻辑泄漏到控制器
解决方案:立即委托给应用服务 -
领域模型依赖框架:
问题:在领域实体中使用 Eloquent
解决方案:严格分离,使用数据映射器 -
过度设计:
问题:简单 CRUD 实施完整 DDD
解决方案:只在复杂领域使用完整 DDD -
层间数据传输:
问题:直接传递 Eloquent 模型
解决方案:使用 DTO 或领域实体作为边界对象
总结
DDD 与 MVC 在 Laravel 中可以完美协同:
- MVC 负责展现层:处理 HTTP 请求/响应、视图渲染
- DDD 负责业务层:建模复杂业务逻辑、维护核心领域
通过分层架构:
- 上层(MVC)依赖于下层(DDD)
- 领域层保持技术无关性
- 基础设施层提供具体实现
这种协同模式允许团队:
- 对复杂核心业务使用 DDD 的严谨建模
- 对简单辅助功能使用 MVC 的高效开发
- 根据需要灵活组合两种模式
最终得到一个既能在核心业务保持领域完整性,又能在其他部分保持开发效率的系统架构。
更多推荐
所有评论(0)