2010-09-01 37 views
5

這是一個有效的對象設計嗎? 我有一個域對象,我注入一個服務並調用一個驗證方法來更新對象的狀態,如果一切順利發送確認消息。代碼如下所示:在域對象方法中封裝服務調用

class Foo { 
    String bar 
    Service emailService 


    public boolean verify() { 
    bar = "foo" 
     if(this.save()) { 
      emailService.sendConfirmation() 
     } 
    } 
} 

Foo.get(1).verify() 

在這樣的情況下調用emailService是否可以接受?有沒有一種設計模式,我可以按照這種情況使用。

謝謝 - 肯

回答

10

沒有什麼錯與實體調用服務。然而,在實例化這些服務時存在一些問題。如果你遵循這條路徑,你必須以某種方式獲得實體創建期間的服務實例,這是有問題的。

直接調用構造函數顯然是一個壞主意(因爲它將實體耦合到服務實現)。

Jimmy Bogard解釋了爲什麼injecting services into entities is a bad idea

而不是它,他建議使用'double dispatch'(有些辯論如果這個名字是合適的)模式來解決這個問題。在這種方法中,域方法調用者向域方法提供服務實現。在你的情況下,它看起來類似的東西:

class Foo { 
    String bar  

    public boolean verify(Service emailService) { 
    bar = "foo" 
     if(this.save()) { 
      emailService.sendConfirmation() 
     } 
    } 
} 

Foo.get(1).verify(new Service(...)) 

最後(但並非最不重要)選項是使用域事件模式。你可以在Udi Dahan's blog上閱讀。在這種方法中,實體只負責發佈由正確的處理程序訂閱的有意義的事件。你可以閱讀所有這些技術的完整比較on my blog

希望幫助

+0

我會說,你應該編碼到這裏的接口。這將使您的實體可以測試,並且如果需要的話可以很容易地更改服務。 ** public bool verify(IConfirmationService emailService)... ** – 2010-09-02 06:22:25

+1

我非常喜歡域名事件模式,喜歡閱讀Udi Dahan的文章,主要是評論和他對他們的回覆。我也認爲,當域事件技術不能解決手頭問題時,應使用雙重調度技術。你還指出了我認爲個人是邪惡的服務定位器,因爲它給人一種錯誤的封裝感。它也使得測試地獄。感謝您的見解和答案。 – ken 2010-09-02 20:25:25

2

我通常會送來自地方的確認(動作?),其中從驗證將被調用。如果驗證的結果是發送許多確認電子郵件,那麼我可能會生成Foo並返回ConfirmationMessage s(域對象),它將封裝所有知識以進行確認。該行動然後能夠排隊這些消息用於分派。儘管如此,如果你的Service是一個接口,你可以注入模擬測試和真正的生產,那麼它看起來很不錯。儘管我認爲域對象最好掌握關於他們自己的知識和邏輯,而不是另一層中的系統(服務)。

+0

+1這是DDD的方式 – Jehof 2010-09-02 06:18:08

+0

+1驗證對象與發送電子郵件無關。想象一下在批處理操作中驗證多個對象 - 您會爲每個對象發送一封電子郵件! – 2010-09-02 11:27:59

+0

這不是一個奇怪的API,讓驗證方法返回一個ConfirmationMessage對象。 API客戶端期望的是操作是否成功。在你的建議中,當驗證操作失敗時你會返回空值? – ken 2010-09-02 20:31:17

3

糟糕的是,你失去了你的域模型的隔離。 您的域模型知道電子郵件服務是純粹的基礎設施。

介紹應用服務可能是一個好主意。 事件模式也可以做到這一點。