2017-07-17 19 views
1

我在學習用ValueObject編碼。我有關於有VO的抽象實現和子類擴展它的問題。孩子們只會實施給定值的驗證方法(電子郵件,用戶名等)。 我的第一個VO看起來如下線在業務規則,這是在構造函數驗證。ValueObject的抽象

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)。所以我想到了一些抽象類實現模式,並讓孩子細化驗證規則。

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沒有泛型類型,我必須像字符串一樣驗證值類型。我不確定它是否適合做這件事,因爲它不是商業規則(我認爲,但我可能是錯的)有人可以告訴我哪種選擇更好,並且與良好實踐兼容嗎?

+0

也許你想看看https://github.com/teneleven/valueobjects,這是https://github.com/nicolopignatelli/valueobjects的克隆。 git(由作者刪除)。 – localheinz

回答

4

我不會那樣做了幾個方面的原因:

  1. 這將與只有一個參數構造函數中的值對象只工作
  2. 在構造函數中的參數不會跟隨從無處不在的語言命名
  3. 的干將不會遵循通用語言命名
  4. 你會不會在構造函數中的參數類型提示,因爲它們是未知的基類
  5. 除非絕對必要(它幾乎從不),否則應該避免域對象的繼承,因爲它將域對象耦合到其他類,並且程序員的認知努力更高:必須知道基類爲了瞭解孩子的課堂;我嘗試favor composition over inheritance

你不用在調用器中調用validate()

5

不要對於不相關的概念使用繼承。價值對象不是現實世界的概念。這是一種在程序中使用的技術。

存在具有一個抽象基類ValueObject,然後由EmailPhoneNumberPostalAddress 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 '@' 
    } 
}