2009-03-05 68 views
4

我一直努力遵循依賴注入的原則,但after reading this article, I know I'm doing something wrong.依賴注入和運行時創建對象

這裏是我的情況:我的應用程序接收到不同類型的物理郵件。所有收到的郵件都會通過我的MailFunnel對象。

當它運行時,MailFunnel接收來自外部的不同類型的消息:框,明信片和雜誌。

每種郵件類型需要以不同的方式處理。例如,如果箱子進來,我可能需要在交付之前記錄重量。因此,我有BoxHandler,PostcardHandlerMagazineHandler對象。

每次有新消息進入我的MailFunnel,我都會實例化一個新的對應的MailHandler對象。

例如:

 
class MailFunnel 
{ 
    void NewMailArrived(Mail mail) 
    { 
    switch (mail.type) 
    { 
     case BOX: 
     BoxHandler * bob = new BoxHandler(shreddingPolicy, maxWeightPolicy); 
     bob->get_to_work(); 
     break; 

     case POSTCARD: 
     PostcardHandler * frank = new PostcardHandler(coolPicturePolicy); 
     frank->get_to_work(); 
     break; 

     case MAGAZINE: 
     MagazineHandler * nancy = new MagazineHandler(censorPolicy); 
     nancy->get_to_work(); 
     break; 
    } 
    } 

    private: 
    MaxWeightPolcy & maxWeightPolicy; 
    ShreddingPolicy & shreddingPolicy; 
    CoolPicturePolicy & coolPicturePolicy; 
    CensorPolicy & censorPolicy; 
} 

一方面,這是偉大的,因爲這意味着,如果我得到五個不同封郵件,我立刻有五種不同的MailHandlers同時工作,照顧生意。但是,這也意味着I'm mixing object creation with application logic - 在依賴注入方面,這是一個很大的難題。

此外,我所有這些政策參考掛在MailFunnel對象MailFunnel真的不需要。 MailFunnel具有這些對象的唯一原因是將它們傳遞給構造函數MailHandler。再次,this is another thing I want to avoid

歡迎提供所有建議。謝謝!

回答

8

這看起來更像是一個工廠給我。將調用get_to_work()方法移出調用並返回處理程序。這種模式對於工廠來說工作得很好。

class MailHandlerFactory 
{ 
    IMailHandler* GetHandler(Mail mail) 
    { 
    switch (mail.type) 
    { 
     case BOX: 
     return new BoxHandler(shreddingPolicy, maxWeightPolicy); 
     break; 

     case POSTCARD: 
     return new PostcardHandler(coolPicturePolicy); 
     break; 

     case MAGAZINE: 
     return new MagazineHandler(censorPolicy); 
     break; 
    } 
    } 

    private: 
    MaxWeightPolcy & maxWeightPolicy; 
    ShreddingPolicy & shreddingPolicy; 
    CoolPicturePolicy & coolPicturePolicy; 
    CensorPolicy & censorPolicy; 
} 

class MailFunnel 
{ 
    MailHandlerFactory* handlerFactory; 

    MailFunnel(MailHandlerFactory* factory) { 
     handlerFactory = factory; 
    } 

    void NewMailArrived(Mail mail) { 
     IMailHandler handler = handlerFactory.GetHandler(mail); 
     handler.get_to_work(); 
    } 
} 
2

爲什麼你不能只有三種重載的方法需要使用不同類型的郵件,然後做適當的事情?或者讓每種類型自己處理。事實上,如果你有類似的東西,你可能應該有其他不同的類型。

基本上做到以下幾點:

1)請郵件抽象類。

2)創建的郵件的三個子類,盒子,明信片,和雜誌

3)給每個子類處理郵件的方法,或集中在一個單獨的HandlerFactory

4)當傳遞到郵件漏斗,只需要調用句柄郵件方法,或者讓HandlerFactory將郵件傳遞給它,然後獲取適當的處理程序。再說一遍,不是到處都有尷尬的開關語句,而是使用語言,這是重載的類型和方法。

如果您的郵件處理變得複雜並且您想要將其取出,您最終可以創建一個郵件處理程序類並將這些策略提取到該類中。

你也可以考慮使用模板方法,因爲它們之間的唯一真正區別似乎是你實例的處理程序,也許你可以簡化它,例如郵件類型決定處理程序,其餘代碼基本上是一樣的。

2

當您看到switch語句時,請考慮多態性。這種設計只能通過修改來擴展。我會重做它,以便通過添加類來添加新行爲。這就是開放/封閉原則的全部內容。

1

有趣的是,你正在向C++項目應用依賴注入;它已在其他地方完成,快速谷歌搜索找到一個谷歌代碼項目Autumn Framework

但是,在採用新框架之前,我會建議先嚐試tvanfosson的回答。