【发布时间】:2021-05-12 05:55:03
【问题描述】:
在学习 DDD 和 cqrs 时,我需要澄清一些事情。在购物环境中,我有一个客户,我认为它是我的聚合根,我想实现更改客户名称的简单用例。
据我所知,这是我使用 DDD/CQRS 实现的。
我的担忧是
- 对于验证,该命令是否还应验证输入以使其与值对象一致,或者是否可以将其留给处理程序?
- 我的整体流程是否正常,还是我严重遗漏了某个地方?
- 如果这个流程是正确的,我看到 Customer Aggregate root 将是一个巨大的类,其中包含许多函数,如 changeName、changeAddress、changePhoneNumber、deleteSavedPaymentMethod 等。 会成为神级,我觉得有点奇怪,这真的是DDD聚合根实现的正确方式吗?
// 值对象
class CustomerName
{
private string $name;
public function __construct(string $name)
{
if(empty($name)){
throw new InvalidNameException();
}
$this->name = $name;
}
}
// 聚合根
class Customer
{
private UUID $id;
private CustomerName $name;
public function __construct(UUID $id, CustomerName $name)
{
$this->id = $id;
$this->name = $name;
}
public function changeName(CustomerName $oldName, CustomerName $newName) {
if($oldName !== $this->name){
throw new InconsistencyException('Probably name was already changed');
}
$this->name = $newName;
}
}
// 命令
class ChangeNameCommand
{
private string $id;
private string $oldName;
private string $newName;
public function __construct(string $id, string $oldName, string $newName)
{
if(empty($id)){ // only check for non empty string
throw new InvalidIDException();
}
$this->id = $id;
$this->oldName = $oldName;
$this->newName = $newName;
}
public function getNewName(): string
{
return $this->newName; // alternately I could return new CustomerName($this->newName)] ?
}
public function getOldName(): string
{
return $this->oldName;
}
public function getID(): string
{
return $this->id;
}
}
//处理程序
class ChangeNameHandler
{
private EventBus $eBus;
public function __construct(EventBus $bus)
{
$this->eBus = $bus;
}
public function handle(ChangeNameCommand $nameCommand) {
try{
// value objects for verification
$newName = new CustomerName($nameCommand->getNewName());
$oldName = new CustomerName($nameCommand->getOldName());
$customerTable = new CustomerTable();
$customerRepo = new CustomerRepo($customerTable);
$id = new UUID($nameCommand->id());
$customer = $customerRepo->find($id);
$customer->changeName($oldName, $newName);
$customerRepo->add($customer);
$event = new CustomerNameChanged($id);
$this->eBus->dispatch($event);
} catch (Exception $e) {
$event = new CustomerNameChangFailed($nameCommand, $e);
$this->eBus->dispatch($event);
}
}
}
//控制器
class Controller
{
public function change($request)
{
$cmd = new ChangeNameCommand($request->id, $request->old_name, $request->new_name);
$eventBus = new EventBus();
$handler = new ChangeNameHandler($eventBus);
$handler->handle($cmd);
}
}
PS。为简洁起见,跳过了 UUID、Repo 等一些类。
【问题讨论】:
标签: php domain-driven-design cqrs ddd-repositories