乐趣区

关于php:剖玄析微聚合-事件溯源

本文转载自【何以解耦】:https://codedecoupled.com/php…

聚合是 DDD(畛域驱动设计)中一个绝对简单的概念。作为 DDD 战术设计中无足轻重的工具,咱们有必要对其了若指掌。

总体来说,聚合(Aggregate)是指一组严密相干的类,他们自成一体造成一个有边界的组织,边界内部的对象只能够通过聚合根(Aggregate Root)与此聚合交互:

聚合常会与泛型 collection 混同,他们的区别在于聚合是绝对于畛域模型而言,而 collection 是一种宽泛的概念。那么具体来说,除了聚合根,聚合外部还有哪些类呢?本文论述一个事件溯源的架构中,常见的几个重要组成部分(类)。

实体

实体为独立事物的建模工具,每个实体都领有惟一标识符,比方 ID, UUIDUsername 等等。大多数状况下,实体是可变的,它的状态会随着工夫的迁徙而扭转。

实体很好了解,如果咱们用 DDD 来剖析 ORM 业务,那么 ORM 中的 Model 能够了解为实体。数据库中的每一条数据都领有本人的 ID(惟一标识符),每条数据的内容也会变化多端。

用实体为用户(User)建模:

class User extends Model
{
    private int $id;

    
    public function __construct(int $id)
    {$this->id = $id;}


    public function changePassword(string $password)
    {// domain code}

}


$user = new User(1);
$user->changePassword();

值对象

值对象是畛域中用来形容,量化或者测量实体的模型。和实体不同,值对象没有惟一的标识符,两个对等的值对象是能够替换的。值对象具备不变性(Immutability),一旦创立当前,一个值对象的属性就定型了,不可更改。

值对象是一个弱小但通常被疏忽的建模工具。应用值对象建模能够大大简化咱们的代码。上面咱们来剖析一下值对象几个个性。

无标识符性

值对象肯定没有诸如 ID, UUID 等等之类的标识符。

不变性

值对象初始化当前,他的值变无奈被更改。咱们在用值对象建模时须要特地留神,不应该给值对象赋予扭转其外部属性的性能。如果须要变异办法时,此办法必须创立一个全新的值对象(见以下 Money::add())。

class Money
{
    private int $amountInCent;

    private string $currency;

    public function __construct(int $amountInCent, string $currency)
    {
        $this->amountInCent = $amountInCent;
        $this->currency = $currency;
    }

    public function getAmountInCent(): int
    {return $this->amountInCent;}

    public function getCurrency(): string
    {return $this->currency;}

    
    public function add(Money $money): Money
    {if ($this->currency !== $this->getCurrency()) {throw new \Exception('You can not add two different currency');
        }
        
        return new Money ($this->amountInCent + $money->getAmountInCent(),
            $this->currency
        );
    }
}
可替换性

值对象的不变性奠定了其可替换性的根底,如果两个值对象的值对等,咱们能够释怀地替换两个值对象。咱们能够这样了解这个概念:如果甲有一张 10 块钱人民币钞票,乙也有一张 10 块钱人民币钞票,他们能够进行对等替换而不会引起利益纠纷。

畛域中很多模型都能够应用值对象来建模,它的个性给予咱们一个平安的,灵便的环境来治理咱们的代码。比方上节中的 $password 就能够应用值对象来实现。

class Password
{
    private string $value;

    public function __construct(string $value)
    {$this->guard($value);
        $this-> value = $value;
    }

    public function toString()
    {return $this->value;}    
    
    private function guard($value)
    {if (empty($value)) {throw new /Exception('invalid password value');
       }
    }
}


$user = new User(1);
$password = new Password($passwordStr);
$user->changePassword($password);

初始化胜利后的 $password 肯定是无效的,因为咱们在初始化中做了防守。值对象为咱们提供了一个平安的模型,接下来的代码中咱们都无需放心 $password 是否合乎业务要求。

聚合根

聚合根的实质是实体,或者说聚合根是一种非凡的实体。聚合根的特殊性体现在它在聚合中的位置,它是聚合对外的惟一接口。如果咱们把聚合设想成一个户口簿,那么聚合根就如同户主,任何户口簿的操作行为都须要通过户主。

畛域事件

畛域事件是畛域中与业务非亲非故的业务事件,它与基础设施,代码框架无关,所以畛域事件不应该是诸如 EmailSentRecordUpdated 之类的极其宽泛的框架事件。

畛域事件在聚合根中产生,而后被存储长久化。畛域事件长久化是最初一个步骤,以此来确保所有的畛域事件的正确性。如有任何异样,畛域事件都不会被谬误地保存起来。

总结

在一个事件溯源的架构中,一个聚合必然是由一个聚合根以及以上一个或多个局部组成。

本文转载自【何以解耦】:https://codedecoupled.com/php…,如果你也对 TDD,DDD 以及简洁代码感兴趣,欢送关注公众号【何以解耦】,一起摸索软件开发之道。

退出移动版