ValueObject的抽象

gar*_*258 1 php oop inheritance abstract-class domain-driven-design

我正在尝试使用ValueObject学习编码.我有关于VO的抽象实现的问题,而子类扩展了它.孩子们只会实现给定值的验证方法(电子邮件,用户名等).我的第一个VO看起来在下面是业务规则,这些规则在构造函数中进行验证.

final class Email {
    private $email;

    public function __construct(string $email)
    {
        $this->validateEmail($email);

        $this->email = $email;
    }

    public function value() : string
    {
        return $this->email;
    }

    private function validateEmail(string $email) : void
    {
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            throw new IncorrectEmailException();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

当我写第二个VO时,我发现了一些不同的模式,只有验证规则(方法validate).所以我想到了一些抽象类实现模式,让child改进验证规则.

abstract class ValueObject {

    protected $value;

    public function __construct($value)
    {
        $this->validate($value);

        $this->value = $value;
    }

    public function value()
    {
        return $value;
    }

    abstract protected function validate($value) : void;
}

final class Email extends ValueObject {
    protected function validate($value) : void
    {
        if (!is_string($value)) {
            throw new \InvalidArgumentException();
        }

        if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
            throw new IncorrectEmailException();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我输掉了一些方法和输入或输出(例如方法'值').PHP没有泛型类型,我必须验证像string这样的值类型.我不确定它是否适合这样做因为它不是商业规则(我认为,但我可能是错的)有人可以告诉我哪个选项更好并且与良好做法兼容?

Con*_*enu 5

我不会这样做有几个原因:

  1. 这仅适用于构造函数中只有一个参数的值对象
  2. 构造函数中的参数不会遵循通用语言的命名
  3. getter 不会遵循无处不在的语言的命名
  4. 您不会对构造函数中的参数进行类型提示,因为它们对于基类是未知的
  5. 你应该避免领域对象的继承,除非它是绝对必要的(几乎从来没有),因为它将你的领域对象耦合到其他类,并且程序员的认知努力更高:人们必须知道基类做什么才能理解儿童班;我尽量支持组合而不是继承

你失去了所有这一切,因为没有调用validate()你的构造函数。


axi*_*iac 5

不要将继承用于不相关的概念.价值对象不是现实世界的概念.这是一种用于程序的技术.

存在具有一个抽象基类没有点ValueObject,然后由扩展Email,PhoneNumber,PostalAddressASO

为每个概念编写一个类并保持简单.例如,不需要单独的验证方法.将验证放在构造函数中,实现__toString()(如果适用)和/或格式化封装值的其他方法,并且应该是全部.

例如:

final class EmailAddress
{
    private $email;

    public function __construct(string $email)
    {
        if (! filter_var($email, FILTER_VALIDATE_EMAIL)) {
            throw new InvalidArgumentException(sprintf("Invalid email '%s'", $email));
        }

        $this->email = $email;
    }

    public function __toString() : string
    {
        return $this->email;
    }

    // For some statistics
    public function getDomain() : string
    {
        // write code here to return only the part after '@'
    }
}
Run Code Online (Sandbox Code Playgroud)