本文目录导读:

在 Laravel 架构中,领域服务(Domain Services) 的放置位置取决于你采用的是传统分层架构还是 DDD(领域驱动设计)风格,以下是两种主流实践方案:
传统 Laravel 分层架构(推荐入门/中小项目)
如果项目没有严格遵循 DDD,而是使用 Laravel 默认的 app/ 目录结构,领域服务可以放在:
app/Services/
└── Domain/
├── OrderService.php
├── PaymentService.php
└── UserDomainService.php
实现示例:
// app/Services/Domain/OrderService.php
namespace App\Services\Domain;
use App\Models\Order;
use App\Repositories\OrderRepository;
use App\Exceptions\InsufficientStockException;
class OrderService
{
public function __construct(
private OrderRepository $repository
) {}
public function placeOrder(array $items, string $userId): Order
{
// 领域逻辑:检查库存、计算总价、创建订单
$this->validateStock($items);
$total = $this->calculateTotal($items);
return $this->repository->create([
'user_id' => $userId,
'items' => $items,
'total' => $total,
'status' => 'pending'
]);
}
private function validateStock(array $items): void
{
foreach ($items as $item) {
if ($item['quantity'] > $item['product']->stock) {
throw new InsufficientStockException($item['product']->name);
}
}
}
}
DDD 风格架构(推荐大型/复杂项目)
对于严格遵循 DDD 的项目,使用 app/Domain/ 目录:
app/Domain/
├── Services/
│ ├── OrderPlacementService.php
│ ├── PaymentService.php
│ └── ShippingService.php
├── Models/
│ ├── Order.php
│ └── Payment.php
├── Repositories/
│ └── OrderRepository.php
└── Events/
└── OrderPlaced.php
DDD 风格示例:
// app/Domain/Services/OrderPlacementService.php
namespace App\Domain\Services;
use App\Domain\Repositories\OrderRepository;
use App\Domain\Events\OrderPlaced;
use App\Domain\ValueObjects\Money;
use Illuminate\Support\Facades\Event;
class OrderPlacementService
{
public function __construct(
private OrderRepository $orderRepo,
private InventoryService $inventory,
private PricingService $pricing
) {}
public function execute(OrderRequest $request): Order
{
// 1. 验证库存
$this->inventory->reserveItems($request->items);
// 2. 计算价格
$total = $this->pricing->calculate($request->items);
// 3. 创建订单实体
$order = new Order(
userId: $request->userId,
items: $request->items,
total: new Money($total)
);
// 4. 持久化
$this->orderRepo->save($order);
// 5. 触发事件
Event::dispatch(new OrderPlaced($order));
return $order;
}
}
使用 Laravel 包(推荐模块化开发)
如果你使用 nWidart/laravel-modules 或类似包,按模块组织:
Modules/
└── Order/
├── Services/
│ └── OrderService.php
├── Entities/
│ └── Order.php
└── Repositories/
└── OrderRepository.php
关键原则
无论放在哪里,请遵循:
| 原则 | 说明 | 反例 |
|---|---|---|
| 业务逻辑 | 领域服务只包含业务规则,不处理 HTTP 请求 | ❌ 在服务里调用 request()->all() |
| 无状态 | 服务不应该持有状态(除了依赖注入) | ❌ 在服务类里定义 public 属性 |
| 单一职责 | 每个服务只处理一个领域关注点 | ❌ UserService 同时处理用户、订单、支付 |
| 依赖抽象 | 依赖接口而非具体实现 | ❌ 直接实例化 Eloquent Model |
什么时候该用领域服务?
| 场景 | 应该使用 |
|---|---|
| 多个实体协同工作(如订单+支付+库存) | ✅ 必须 |
| 复杂事务性操作 | ✅ 推荐 |
| 简单 CRUD | ❌ 直接使用 Repository 或 Model |
| 只有一个实体的简单规则 | ❌ 放在实体方法里 |
避免的常见错误
// ❌ 错误:在 Controller 里写领域逻辑
class OrderController {
public function store(Request $request) {
// 检查库存、计算价格... 太多逻辑在控制器
}
}
// ✅ 正确:控制器只负责编排
class OrderController {
public function store(Request $request) {
$order = app(OrderService::class)->placeOrder(
$request->items,
auth()->id()
);
return response()->json($order, 201);
}
}
- 传统 Laravel:
app/Services/Domain/ - DDD:
app/Domain/Services/ - 模块化:
Modules/{Module}/Services/
选择哪种取决于项目规模和团队规范,对于大多数 Laravel 项目,app/Services/Domain/ 是最平衡的选择。