本文目录导读:

- 什么是领域模型
- 基础领域模型示例
- 聚合根(Aggregate Root)
- 仓储模式(Repository Pattern)
- 领域服务(Domain Service)
- 领域事件(Domain Events)
- 应用层(Application Layer)
- 最佳实践
我来详细讲解PHP中领域模型的实现方法。
什么是领域模型
领域模型是DDD(领域驱动设计)中的核心概念,它将业务逻辑和规则封装在模型对象中,而不是散落在服务层或控制器中。
基础领域模型示例
实体(Entity)
<?php
class Order
{
private string $id;
private string $customerId;
private array $items = [];
private string $status;
private float $totalAmount;
private \DateTimeImmutable $createdAt;
public function __construct(string $customerId, string $id = null)
{
$this->id = $id ?? uniqid('order_');
$this->customerId = $customerId;
$this->status = 'pending';
$this->createdAt = new \DateTimeImmutable();
}
public function addItem(OrderItem $item): void
{
// 业务规则:订单已支付不能再添加商品
if ($this->status === 'paid') {
throw new \DomainException('已支付的订单不能添加商品');
}
$this->items[] = $item;
$this->recalculateTotal();
}
public function removeItem(string $itemId): void
{
// 业务规则验证
if ($this->status === 'paid') {
throw new \DomainException('已支付的订单不能移除商品');
}
$this->items = array_filter(
$this->items,
fn(OrderItem $item) => $item->getId() !== $itemId
);
$this->recalculateTotal();
}
public function checkout(): void
{
if (empty($this->items)) {
throw new \DomainException('订单没有商品不能结算');
}
if ($this->status !== 'pending') {
throw new \DomainException('订单状态不正确');
}
$this->status = 'paid';
$this->processPayment();
}
private function recalculateTotal(): void
{
$this->totalAmount = array_sum(
array_map(fn(OrderItem $item) => $item->getSubtotal(), $this->items)
);
}
private function processPayment(): void
{
// 支付逻辑
}
// Getters...
}
值对象(Value Object)
<?php
class Money
{
private float $amount;
private string $currency;
public function __construct(float $amount, string $currency)
{
if ($amount < 0) {
throw new \InvalidArgumentException('金额不能为负数');
}
$this->amount = $amount;
$this->currency = $currency;
}
public function add(Money $other): Money
{
if ($this->currency !== $other->currency) {
throw new \DomainException('货币类型不一致');
}
return new Money(
$this->amount + $other->amount,
$this->currency
);
}
public function multiply(float $factor): Money
{
return new Money($this->amount * $factor, $this->currency);
}
// Getters
public function getAmount(): float { return $this->amount; }
public function getCurrency(): string { return $this->currency; }
// 值对象应该有equals方法
public function equals(Money $other): bool
{
return $this->amount === $other->amount
&& $this->currency === $other->currency;
}
}
// 更复杂的值对象
class Address
{
private string $street;
private string $city;
private string $country;
private string $postalCode;
public function __construct(string $street, string $city, string $country, string $postalCode)
{
$this->street = $street;
$this->city = $city;
$this->country = $country;
$this->postalCode = $postalCode;
}
public function format(): string
{
return sprintf('%s, %s, %s %s',
$this->street,
$this->city,
$this->country,
$this->postalCode
);
}
}
聚合根(Aggregate Root)
<?php
class Customer implements AggregateRoot
{
private string $id;
private string $name;
private string $email;
private array $addresses = [];
private array $orders = [];
public function __construct(string $name, string $email)
{
$this->id = uniqid('cust_');
$this->name = $name;
$this->email = $email;
}
public function placeOrder(Order $order): void
{
if ($order->getCustomerId() !== $this->id) {
throw new \DomainException('订单不属于该客户');
}
$this->orders[] = $order;
$order->setCustomer($this);
// 触发领域事件
$this->raiseEvent(new OrderPlaced($order));
}
public function addAddress(Address $address): void
{
if (count($this->addresses) >= 5) {
throw new \DomainException('地址数量不能超过5个');
}
$this->addresses[] = $address;
}
public function changeEmail(string $newEmail): void
{
if (!filter_var($newEmail, FILTER_VALIDATE_EMAIL)) {
throw new \InvalidArgumentException('邮箱格式不正确');
}
$this->email = $newEmail;
}
// 领域事件处理
private array $events = [];
protected function raiseEvent(object $event): void
{
$this->events[] = $event;
}
public function releaseEvents(): array
{
$events = $this->events;
$this->events = [];
return $events;
}
}
// 聚合根接口
interface AggregateRoot
{
public function releaseEvents(): array;
}
仓储模式(Repository Pattern)
<?php
interface OrderRepository
{
public function find(string $id): ?Order;
public function save(Order $order): void;
public function delete(Order $order): void;
public function findByCustomer(string $customerId): array;
}
// 数据库实现
class MysqlOrderRepository implements OrderRepository
{
private PDO $db;
private EventDispatcher $eventDispatcher;
public function __construct(PDO $db, EventDispatcher $eventDispatcher)
{
$this->db = $db;
$this->eventDispatcher = $eventDispatcher;
}
public function find(string $id): ?Order
{
// 数据映射逻辑
$stmt = $this->db->prepare('SELECT * FROM orders WHERE id = ?');
$stmt->execute([$id]);
$data = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$data) {
return null;
}
return $this->mapToOrder($data);
}
public function save(Order $order): void
{
// 保存订单
$stmt = $this->db->prepare(
'INSERT INTO orders (id, customer_id, status, total_amount, created_at)
VALUES (?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE status = ?, total_amount = ?'
);
$stmt->execute([
$order->getId(),
$order->getCustomerId(),
$order->getStatus(),
$order->getTotalAmount(),
$order->getCreatedAt()->format('Y-m-d H:i:s'),
$order->getStatus(),
$order->getTotalAmount()
]);
// 保存订单项
$this->saveItems($order);
// 发送领域事件
foreach ($order->releaseEvents() as $event) {
$this->eventDispatcher->dispatch($event);
}
}
public function delete(Order $order): void
{
$stmt = $this->db->prepare('DELETE FROM orders WHERE id = ?');
$stmt->execute([$order->getId()]);
}
public function findByCustomer(string $customerId): array
{
// 查询逻辑
return [];
}
private function mapToOrder(array $data): Order
{
$order = new Order($data['customer_id'], $data['id']);
// 设置其他属性...
return $order;
}
private function saveItems(Order $order): void
{
// 保存订单项逻辑
}
}
领域服务(Domain Service)
<?php
class OrderService
{
private OrderRepository $orderRepository;
private CustomerRepository $customerRepository;
private PricingService $pricingService;
public function __construct(
OrderRepository $orderRepository,
CustomerRepository $customerRepository,
PricingService $pricingService
) {
$this->orderRepository = $orderRepository;
$this->customerRepository = $customerRepository;
$this->pricingService = $pricingService;
}
public function createOrder(string $customerId, array $items): Order
{
$customer = $this->customerRepository->find($customerId);
if (!$customer) {
throw new \DomainException('客户不存在');
}
$order = new Order($customerId);
foreach ($items as $item) {
$order->addItem($this->createOrderItem($item));
}
$this->applyDiscount($order, $customer);
$this->orderRepository->save($order);
return $order;
}
private function createOrderItem(array $data): OrderItem
{
$price = $this->pricingService->calculatePrice(
$data['product_id'],
$data['quantity']
);
return new OrderItem(
$data['product_id'],
$data['quantity'],
$price
);
}
private function applyDiscount(Order $order, Customer $customer): void
{
if ($customer->isVip()) {
$discount = $order->getTotalAmount() * 0.1;
$order->applyDiscount($discount);
}
}
}
领域事件(Domain Events)
<?php
// 事件定义
class OrderPlaced
{
public function __construct(
public readonly string $orderId,
public readonly string $customerId,
public readonly float $totalAmount,
public readonly \DateTimeImmutable $occurredAt = new \DateTimeImmutable()
) {}
}
class OrderPaid
{
public function __construct(
public readonly string $orderId,
public readonly float $amountPaid,
public readonly \DateTimeImmutable $occurredAt = new \DateTimeImmutable()
) {}
}
// 事件分发器
class EventDispatcher
{
private array $listeners = [];
public function listen(string $eventClass, callable $listener): void
{
$this->listeners[$eventClass][] = $listener;
}
public function dispatch(object $event): void
{
$eventClass = get_class($event);
foreach ($this->listeners[$eventClass] ?? [] as $listener) {
$listener($event);
}
}
}
// 事件处理器
class OrderEventHandler
{
public function handleOrderPlaced(OrderPlaced $event): void
{
// 发送通知
$this->sendEmail($event->customerId, '订单已创建');
// 更新库存
$this->updateInventory($event->orderId);
}
public function handleOrderPaid(OrderPaid $event): void
{
// 生成发票
$this->generateInvoice($event->orderId);
// 更新客户累计消费
$this->updateCustomerSpending($event->customerId, $event->amountPaid);
}
// 其他处理方法...
}
应用层(Application Layer)
<?php
class OrderApplication
{
private OrderService $orderService;
private OrderRepository $orderRepository;
private EventDispatcher $eventDispatcher;
public function __construct(
OrderService $orderService,
OrderRepository $orderRepository,
EventDispatcher $eventDispatcher
) {
$this->orderService = $orderService;
$this->orderRepository = $orderRepository;
$this->eventDispatcher = $eventDispatcher;
}
public function placeOrder(array $request): array
{
try {
$order = $this->orderService->createOrder(
$request['customer_id'],
$request['items']
);
return [
'success' => true,
'order_id' => $order->getId()
];
} catch (\DomainException $e) {
return [
'success' => false,
'error' => $e->getMessage()
];
}
}
public function getOrderDetail(string $orderId): array
{
$order = $this->orderRepository->find($orderId);
if (!$order) {
throw new \RuntimeException('订单不存在');
}
return $this->serializeOrder($order);
}
private function serializeOrder(Order $order): array
{
return [
'id' => $order->getId(),
'items' => array_map(
fn($item) => [
'product_id' => $item->getProductId(),
'quantity' => $item->getQuantity(),
'price' => $item->getPrice()
],
$order->getItems()
),
'total' => $order->getTotalAmount(),
'status' => $order->getStatus()
];
}
}
最佳实践
目录结构
src/
├── Domain/
│ ├── Entity/
│ │ ├── Order.php
│ │ └── Customer.php
│ ├── ValueObject/
│ │ ├── Money.php
│ │ └── Address.php
│ ├── Repository/
│ │ └── OrderRepository.php
│ ├── Service/
│ │ └── OrderService.php
│ └── Event/
│ ├── OrderPlaced.php
│ └── OrderEventHandler.php
├── Infrastructure/
│ └── Persistence/
│ └── MysqlOrderRepository.php
└── Application/
└── OrderApplication.php
关键设计原则
- 实体有ID,值对象没有
- 业务规则在实体内部,不在服务层
- 仓储只负责持久化,不处理业务逻辑
- 通过领域事件解耦不同模块
- 应用层作为薄层,不包含业务逻辑
领域模型模式让业务代码更清晰、可维护,但也需要适度使用,避免过度设计,对于简单项目,使用传统的ActiveRecord模式可能更加合适。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播