Note : This article is the translate of this article. I use Google Translate for help me to write in english. Please, if you read wrong phrase send me the correct by one comment.
In a refactoring sprint, I found that my main aggregate class took much overweight.
I had exceeded 750 lines of code with, in many actions, a « switch » or a dozen « IF ». This did not please me very much because, if a change was required with this level, the amendment would be difficult.
Taking a step back on my code (it is always a good idea to step back and re-read his code to someone else) I realized that my class had defined constants 5 and a property « state « used in all the » switch « or » if « . A little research and rereading the book « Design Pattern – Head First », I fell on the design pattern « Status ».
On reflection and looking at the code that implements this pattern, I decided to implement my aggregate.
Thus begins an intense reflection!
Since the methods related to the state are redirected directly to the object « state » current, how to make the events from the object « state »? How to change my state in aggregate? How not to expose the `setState () method to prevent an` external element does not change the state of the aggregate?
All these issues have a simple answer. But for that, let’s take them one by one.
How to send events from the « state » object?
By storing it in an instance variable of type « table. » The aggregate will recover after the execution of the action to issue them.
How to change the state in my remote?
It does not change location … It’s always in the protected methods apply … `()`. They are the only empowered to modify the internal state of the aggregate.
How not to expose the `setState () method to prevent an` external element does not change the state of the aggregate?
The previous answer there also answers! There is no `setState ()` function. The « state » objects are instantiated and assigned directly to the events of the application methods.
In the end, the two design patterns are perfectly compatible and produce a very effective composition.
Adding a condition is now possible by the application of the « State pattern. » Now my class aggregate has lost more than 250 lines of code and all « if » and « switch » disappeared.
The implementation with Broadway :
<?php interface State { public function change(); public function getEvents(); } abstract class BaseState implements State { private $events; private $aggregate; /** * The aggregate link is for acces to property of aggegate. */ public function __construct($aggregate) { $this->aggregate = $aggregate; } /** * return all events not sent */ public function getEvents() { $events = $this->events; $this->events = []; return $events; } private function addEvent($event) { $this->events[] = $event; } } class FirstState extends BaseState { public function change() { // Store event into state object $this->addEvent(new ChangeEvent($this->aggregate->getAggregateRootId())); } } class SecondState extends BaseState { public function change() { //No change throw new \Exception("Unable to change the state !"); } }
Agregate and Event :
<?php use Broadway\EventSourcing\EventSourcedAggregateRoot; use FirstState; use SecondState; class Agregat extends EventSourcedAggregateRoot { private $id; private $state; public function getAggregateRootId() { return $this->id; } public static function make($id) { //... $this->apply(new MakeEvent($this->getAggregateRootId())); } protected function applyMakeEvent(MakeEvent $event) { $this->id = $event->getId(); $this->state = new FirstState($this); } public function change() { $this->state->change(); $this->applyMany($this->state->getEvents()); } protected function applyChange(ChangeEvent $event) { $this->state = new SecondState($this); } private function applyMany(array $events) { foreach ($events as $event) { $this->apply($event); } } } class ChangeEvent { private $id; public function __construct($id) { $this->id = $id; } public function getId() { return $this->id; } } class MakeEvent { private $id; public function __construct($id) { $this->id = $id; } public function getId() { return $this->id; } }
This branch on my test-broadway repository apply this pattern. Write a comment if you need help or if you want speak…
1 réflexion sur « [Updated] DDD with Broadway and the Design Pattern State »
Les commentaires sont fermés.