我正在尝试使用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();
}
}
}
当我写第二个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();
}
}
}
我输掉了一些方法和输入或输出(例如方法'值')。 PHP没有泛型类型,我必须验证像string这样的值类型。我不确定它是否适合这样做,因为它不是商业规则(我认为,但我可能是错的)有人可以告诉我哪个选项更好并且与良好做法兼容吗?
答案 0 :(得分:5)
不要对不相关的概念使用继承。价值对象不是现实世界的概念。这是一种用于程序的技术。
没有必要设置一个抽象基类ValueObject
,然后由Email
,PhoneNumber
,PostalAddress
a.s.o扩展。
为每个概念编写一个类并保持简单。例如,不需要单独的验证方法。将验证放在构造函数中,实现__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 '@'
}
}
答案 1 :(得分:4)
我不会这样做有几个原因:
你因为没有在你的构造函数中调用validate()
而放弃了所有这些。