DDD(领域驱动设计)与 MVC(模型-视图-控制器)的区别
维度 | MVC | DDD | 解析 |
---|---|---|---|
核心目标 | 分离界面与业务逻辑 | 解决复杂业务领域问题 | MVC关注技术分层,DDD专注业务建模 |
设计起点 | 数据库/技术实现 | 业务领域模型 | MVC常以数据表设计开始,DDD从业务概念和规则出发 |
模型定义 | 数据容器(常为贫血模型) | 富含行为的业务实体 | MVC模型多为getter/setter,DDD模型封装业务规则 |
分层逻辑 | 技术分层(视图-控制-模型) | 业务分层(领域/应用/基础设施/接口) | DDD通过分层保护核心业务不受技术实现污染 |
架构重心 | 请求-响应流程 | 领域模型演进 | MVC优化请求处理,DDD优化业务知识沉淀 |
数据访问 | 直接调用ORM(如Eloquent) | 通过仓储抽象 | DDD用接口隔离持久化细节,支持多实现 |
业务逻辑位置 | 常分散在控制器/服务类 | 内聚在领域模型中 | DDD确保业务规则与数据绑定,避免贫血模型 |
代码组织 | 按技术角色(Controllers, Models等) | 按业务子域(Order, User, Payment) | DDD的结构映射业务语义,便于定位功能 |
适用场景 | CRUD应用/简单业务 | 高复杂性业务系统(电商、金融等) | DDD的复杂度在中小型项目中可能过度 |
核心区别深度解析
1. 模型本质差异
MVC模型(贫血模型):
// MVC典型模型 (贫血)
class Order extends Model {
// 仅有属性和简单访问方法
protected $fillable = ['total', 'status'];
public function user() {
return $this->belongsTo(User::class);
}
}
// 业务逻辑泄漏到控制器
class OrderController {
public function complete(Order $order) {
if($order->status !== 'paid') { // 业务规则暴露在控制器
abort(403, '订单未支付');
}
$order->update(['status' => 'completed']); // 简单数据操作
}
}
DDD领域模型(充血模型):
// DDD领域模型
class Order {
private OrderId $id;
private Money $total;
private OrderStatus $status;
public function __construct(OrderId $id, Money $total) {
$this->id = $id;
$this->total = $total;
$this->status = OrderStatus::PENDING;
}
// 业务行为内聚在模型中
public function complete(): void {
if(!$this->status->canBeCompleted()) { // 规则封装在值对象中
throw new OrderCompletionException();
}
$this->status = OrderStatus::COMPLETED;
$this->addEvent(new OrderCompleted($this->id)); // 领域事件
}
}
// 应用层协调
class CompleteOrderService {
public function execute(OrderId $id) {
$order = $this->repository->find($id);
$order->complete(); // 调用领域行为
$this->repository->save($order);
}
}
2. 数据访问方式对比
MVC直接耦合持久化:
// 直接使用Eloquent
$orders = Order::where('status', 'completed')->with('user')->get();
DDD通过仓储抽象:
// 领域层定义接口
interface OrderRepository {
public function findCompletedOrders(): Collection;
}
// 基础设施层实现
class EloquentOrderRepository implements OrderRepository {
public function findCompletedOrders() {
// 返回领域对象而非Eloquent模型
return OrderModel::completed()->get()->map(fn($model) => $this->toDomain($model));
}
}
// 应用层调用
$orders = $orderRepository->findCompletedOrders(); // 不依赖具体ORM
3. 业务规则处理差异
MVC的典型问题:
// 业务规则分散在服务类
class OrderService {
public function applyDiscount(Order $order, Discount $discount) {
// 业务逻辑泄漏到服务层
if($order->created_at->diffInDays() > 30) {
throw new DiscountExpiredException();
}
$newTotal = $order->total - $discount->amount; // 计算放在服务层
$order->update(['total' => $newTotal]);
}
}
DDD的正确实践:
// 领域模型中封装规则
class Order {
public function applyDiscount(Discount $discount): void {
if(!$discount->isApplicableTo($this)) { // 规则委托给值对象
throw new DiscountNotApplicableException();
}
$this->total = $this->total->subtract($discount->amount); // 计算内聚
}
}
// 值对象维护业务规则
class Discount {
public function isApplicableTo(Order $order): bool {
return $this->validPeriod->contains($order->createdAt);
}
}
演进关系图解
传统MVC:
请求 → 控制器 → 服务类 → 贫血模型 → 数据库
DDD分层:
请求 → 控制器(接口层)
→ 应用服务(应用层)
→ 领域模型/领域服务(领域层)
← 仓储接口(领域层)
→ 仓储实现(基础设施层)
→ 数据库
何时选择哪种架构?
场景 | 推荐架构 | 原因 |
---|---|---|
管理后台/简单CRUD | ✅ MVC | 快速开发,避免过度设计 |
中等复杂度业务系统 | ⚠️ 改良MVC | 增加服务层,部分引入DDD概念 |
核心复杂业务域 | ✅ DDD | 应对业务复杂度,保持代码可维护性 |
微服务中的核心服务 | ✅ DDD | 清晰边界,独立演进 |
遗留系统重构 | ✅ 渐进式DDD | 从核心子域开始逐步改造 |
关键洞察:DDD不是替代MVC,而是在复杂业务场景下对MVC的深化演进。Laravel项目中可混合使用:非核心模块用MVC,核心业务用DDD。
混合架构实践(Laravel特定)
app/
├── Http/ # MVC部分 (简单模块)
│ ├── Controllers/Admin # 后台控制器
│ └── Requests/
│
└── Domains/ # DDD部分 (核心业务)
└── Inventory/ # 库存子域
├── Models/ # 领域模型
├── Repositories/ # 仓储接口
├── Services/ # 领域服务
└── Actions/ # 应用层操作
这种结构允许团队:
- 对商品管理等复杂功能使用DDD
- 对日志查看等简单功能保持MVC
- 逐步重构关键业务到Domains目录