CQRS (Command and Query Responsibility Segregation) 是一種在現(xiàn)代軟件開發(fā)中越來越普遍的架構(gòu)模式。 它通過分離寫操作(指令)和讀操作(查詢)來提高系統(tǒng)的可讀性、可擴展性和可維護性。 最近,我嘗試了一些CQRS實現(xiàn),其中一個是使用PHP的 cqrs-example-php 。
這個例子實現(xiàn)了一個基本的事件存儲庫和CQRS框架。 它包括兩個主要部分和一個示例實現(xiàn)。 一部分是用于定義事件、領(lǐng)域模型和存儲庫的核心框架。 另一部分是建立在核心框架上的一個示例應(yīng)用,它演示了如何使用CQRS設(shè)計模式創(chuàng)建一個簡單的任務(wù)列表應(yīng)用。
讓我們先看一下實現(xiàn)的基礎(chǔ)框架。 首先,事件是最小化的信息單元,它代表了一些已經(jīng)發(fā)生的領(lǐng)域事件。 事件通常有一個相關(guān)的名稱和一組屬性。 在cqrs-example-php中,事件可以通過實現(xiàn) `CQRS\Event` 接口來自定義。
```php
interface Event {
public function getName(): string;
public function getPayload(): array;
public function occurredOn(): DateTimeImmutable;
}
```
事件存儲庫負責(zé)存儲事件流和檢索事件流。 在cqrs-example-php中,存儲庫由一個抽象類 `CQRS\EventStore\EventStore` 實現(xiàn),并由不同的存儲庫驅(qū)動支持。 以下是存儲庫框架的主要組成部分:
```php
abstract class EventStore {
public function appendTo(UUID $aggregateUUID, EventStream $eventStream): void;
public function readAllEvents(): EventStream;
public function readEventsByAggregate(UUID $aggregateUUID): EventStream;
public function getAggregateHistory(UUID $aggregateUUID): AggregateHistory;
public function getLastEventUUID(): UUID;
}
class EventStream implements IteratorAggregate {
public function __construct(Event... $events);
}
class AggregateHistory implements IteratorAggregate {
public function __construct(UUID $aggregateUUID, EventStream $eventStream);
}
```
存儲庫驅(qū)動程序主要負責(zé)與特定的事件存儲庫集成。 cqrs-example-php 支持多個簡單的事件存儲庫實現(xiàn),包括內(nèi)存事件存儲庫、Redis事件存儲庫和SQLite事件存儲庫。 如果你想嘗試使用自己的事件存儲庫,只需要實現(xiàn) `CQRS\EventStore\EventStore` 類即可。
```php
class InMemoryEventStore extends EventStore {
public function __construct();
}
class RedisEventStore extends EventStore {
public function __construct(string $dsn);
}
class SQLiteEventStore extends EventStore {
public function __construct(string $dsn);
}
```
現(xiàn)在,我們看看如何構(gòu)建一個簡單的任務(wù)列表應(yīng)用程序。 首先,我們需要確定這個應(yīng)用程序的主要目標(biāo)。 在本例中,我們要實現(xiàn)一個具有以下功能的任務(wù)列表應(yīng)用:
- 創(chuàng)建新任務(wù)
- 列出所有任務(wù)
- 根據(jù) ID 獲取任務(wù)
- 完成任務(wù)并更新其狀態(tài)
我們需要將每個功能作為一個單獨的操作來實現(xiàn)。 這就是CQRS的核心理念。
看看第一個操作:創(chuàng)建新任務(wù)。 我們需要編寫一個命令處理程序,該處理程序?qū)⑻幚磔斎霐?shù)據(jù)并包裝成應(yīng)該添加到事件存儲庫中的事件。 在cqrs-example-php中,命令在 `CQRS\Command` 接口中定義,我們需要實現(xiàn)我們自己的命令類。
```php
interface Command {
public function getName(): string;
public function getData(): array;
}
class CreateTaskCommand implements Command {
public function __construct(string $name) {
// ...
}
public function getName(): string {
return 'createTask';
}
public function getData(): array {
return [
'name' =>$this->name
];
}
}
```
現(xiàn)在我們需要編寫命令處理程序,將創(chuàng)建新任務(wù)并將其添加到事件存儲庫中。 在cqrs-example-php中,命令處理程序有一個映射表,該映射表將命令名稱映射到實際的處理程序。
```php
$commandBus = new CQRS\CommandBus\CommandBus();
$commandBus->register('createTask', new CreateTaskHandler($eventStore));
```
注意,在這里我忽略了依賴項注入,為了避免混淆,將 `EventStore` 注入命令處理程序的構(gòu)造函數(shù)中。
最后,我們需要編寫一個查詢處理程序,以便用戶可以查看任務(wù)列表并更新其狀態(tài)。 因為這個應(yīng)用程序非常簡單,我們將把所有的讀取和寫入操作放在一個處理程序中。 在cqrs-example-php中,這個概念被稱為“查詢服務(wù)”。
```php
class TaskQueryHandler implements CQRS\QueryHandler {
public function handle($query) {
// ...
}
}
```
有了處理程序和查詢服務(wù),我們現(xiàn)在可以使用這些部件來構(gòu)建我們的整個應(yīng)用程序了。
```php
$eventStore = ... // initialize event store
$commandBus = new CQRS\CommandBus\CommandBus();
$commandBus->register('createTask', new CreateTaskHandler($eventStore));
$commandBus->register('completeTask', new UpdateTaskHandler($eventStore));
$taskService = new TaskQueryHandler($eventStore);
// create a new task
$commandBus->dispatch(new CreateTaskCommand('Buy milk'));
// list all tasks
$tasks = $taskService->handle(new AllTasksQuery());
// update task status
$commandBus->dispatch(new UpdateTaskCommand($taskId, TaskStatus::COMPLETED));
```
cqrs-example-php是一個相當(dāng)完整的示例,涵蓋了許多與CQRS架構(gòu)相關(guān)的概念。 它也很容易修改和擴展。 可以通過查看 README 文件和示例實現(xiàn)代碼來更好地理解其中的細節(jié)。
網(wǎng)站導(dǎo)航
- zblogPHP模板zbpkf
- zblog免費模板zblogfree
- zblog模板學(xué)習(xí)zblogxuexi
- zblogPHP仿站zbpfang