我有一个与松散耦合的OOP设计有关的问题。 考虑我们有一个简单的价值对象,如电子邮件
final class Email
{
private $_email;
public function __construct($email)
{
self::isValid($email);
$this->_email = $email;
}
public function getEmail()
{
return $this->_email;
}
public static function isValid($email)
{
// some validation logic goes here
return true;
}
}
在我想实际实现isValid方法之前,一切都很简单明了。 我在这里有两个选择:
1)实现我自己的验证逻辑,这可能是非常丑陋的事情:
public static function isValid($email)
{
$v = preg_match(
'/^[-a-z0-9!#$%&\'*+\/\=?^_`{|}~]+(?:\.[-a-z0-9!#$%&\'*+\/\=?^_`{|}~]+)*@(?:[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?\.)*(?:aero|arpa|asia|biz|cat|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|pro|tel|travel|pro|[a-z][a-z])$/',
$email
);
return $v > 0;
}
2)使用一些内置框架验证器
public static function isValid($email)
{
$validator = new Zend_Validate_Email(); // tight-coupling detected!
return $validator->isValid($email);
}
我真的不想遵循第一种方式,因为我不想重新发明轮子我也不想重复代码,所以我坚持第二种方式。
如果我按照第二种方式遇到问题 - 我的课程依赖于另一个框架类。
我的实际问题是否可以直接在实体/值对象中使用低级基础结构类而不使用依赖注入?
如果我“正确”地实现这个例子,代码将变得更加复杂,仅仅是为了松散耦合。我将不得不创建一个EmailFactory,它将为我的Value Object(Email)类提供一个预先配置的EmailValidator实例,该实例将在isValid函数中使用...
答案 0 :(得分:0)
只要验证函数不需要外部资源,我就会直接重用依赖项并避免它的注入。
域对象封装了域规则,并且应包含确保这些规则的所有必要信息。它的设计更多地围绕高内聚而不是低耦合(聚合本身的概念本身就是减少相互依赖性的一种手段)。
示例中的Email
类应该是电子邮件地址验证的单点故障。如果所有域对象都通过该类验证电子邮件,那么重用现有框架(甚至第三方)功能是一个实现细节,而不是松散耦合的问题。如果验证规则发生变化,您无论如何都必须重新实现该功能 - 使用Zend_Validate_Email
或一些自定义代码。
将验证逻辑注入实体或值对象会带来很多问题:
EmailValidator
类引入界面违反了Reused Abstractions Principle isValid
上调用静态EMail
方法是不可能的只有在验证逻辑需要外部资源的极少数情况下,我倾向于使用具有注入服务的工厂,该服务在创建域对象时进行验证 - 但仅在重新考虑域模型的设计之后。