1

我有一个与松耦合 OOP 设计有关的问题。考虑我们有一个简单的值对象,比如 Email

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,它会为我的值对象 (Email) 类提供一个预配置的 EmailValidator 实例,该实例将在 isValid 函数中使用……</p>

4

1 回答 1

0

只要验证函数不需要外部资源,我就会直接重用依赖项并避免它的注入。

域对象封装了域规则,并应包含确保这些规则所需的所有必要信息。它的设计更多是围绕高内聚而不是低耦合(聚合的概念本身就是减少相互依赖的一种手段)。

您示例中的Email类应该是电子邮件地址验证的单点故障。如果所有域对象都通过该类验证电子邮件,那么重用现有框架(甚至第三方)功能是一个实现细节,并且在松散耦合方面不会成为问题。如果验证规则发生变化,您无论如何都必须重新实现该功能 - 使用Zend_Validate_Email或一些自定义代码。

将验证逻辑注入实体或值对象会带来很多问题:

  • 属于域对象的逻辑将被移动到另一个类
  • 通常不建议将服务注入实体
  • 只为类引入接口EmailValidator违反了重用抽象原则
  • 调用静态isValid方法EMail是不可能的

只有在验证逻辑需要外部资源的极少数情况下,我才会倾向于使用带有注入服务的工厂来验证域对象的创建——但只有在重新考虑域模型的设计之后。

于 2014-02-24T16:33:28.050 回答