2009-03-05 62 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的回答。