2009-03-05 9 views
4

Ich habe versucht, die Prinzipien der Dependency Injection zu folgen, aber after reading this article, I know I'm doing something wrong.Dependency Injection und Runtime Objekterstellung

Hier ist meine Situation: Meine Anwendung erhält verschiedene Arten von physischer Post. Die gesamte eingehende Mail läuft durch mein MailFunnel Objekt.

Während es läuft, empfängt MailFunnel verschiedene Arten von Nachrichten von außen: Box, Postkarte und Magazin.

Jeder Mail-Typ muss anders behandelt werden. Zum Beispiel, wenn eine Box kommt, muss ich möglicherweise das Gewicht vor der Auslieferung aufnehmen. Folglich habe ich BoxHandler, PostcardHandler und MagazineHandler Objekte.

Jedes Mal, wenn eine neue Nachricht mein MailFunnel kommt, instanziieren ich ein neueMailHandler Objekt entspricht.

Zum Beispiel:

 
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; 
} 

Auf der einen Seite, das ist großartig, weil es bedeutet, dass, wenn ich fünf verschiedene Poststücke erhalten in, habe ich sofort fünf unterschiedliche MailHandlers gleichzeitig arbeiten von Geschäft zu kümmern. Dies bedeutet aber auch, dass I'm mixing object creation with application logic - ein großes No-No, wenn es um Dependency Injection geht.

Auch habe ich alle diese Politik Referenzen herumhängen in meinem MailFunnel Objekt, das MailFunnel wirklich nicht benötigt. Der einzige Grund, warum MailFunnel diese Objekte hat, besteht darin, sie an die MailHandler Konstruktoren zu übergeben. Wiederum this is another thing I want to avoid.

Alle Empfehlungen sind willkommen. Vielen Dank!

Antwort

8

Das sieht für mich eher wie eine Fabrik aus. Verschieben Sie den Aufruf der Methode get_to_work() aus dem Aufruf und geben Sie den Handler zurück. Das Muster funktioniert ziemlich gut für eine Fabrik.

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

Warum können Sie nicht nur drei Methoden, die überladen werden, die verschiedenen Arten von E-Mail haben, und dann die entsprechende Sache tun? Oder jeder Typ selbst handhaben.

In der Tat, wenn Sie etwas wie Typ haben, sind die Chancen, dass Sie tatsächlich verschiedene Arten haben.

Grundsätzlich wie folgt vor:

1) Stellen Sie die Mail-Klasse abstrakt.

2) Erstellen Sie eine drei Unterklassen Mail, Box, Postkarte und Magazine

3) jeweils Geben Sie eine Methode Unterklasse Mail zu handhaben, oder in einem separaten HandlerFactory zentralisieren

4) Wenn übergeben an den Mail-Trichter, rufen Sie einfach die Handle-Mail-Methode auf oder lassen Sie die HandlerFactory die Mail weiterleiten und holen Sie den entsprechenden Handler zurück. Verwenden Sie statt ungeschickter Switch-Anweisungen die Sprache, für die das Überladen von Typen und Methoden zuständig ist.

Wenn Ihre E-Mail-Verarbeitung komplex wird und Sie sie entfernen möchten, können Sie eventuell eine Mail-Handler-Klasse erstellen und diese Richtlinien daraus extrahieren.Sie können auch die Verwendung einer Template-Methode in Erwägung ziehen, da der einzige wirkliche Unterschied zwischen den beiden scheinbar der Handler Ihrer Instanz ist, vielleicht könnten Sie ihn vereinfachen, so dass der Mail-Typ den Handler und den Rest des Codes bestimmt ist im Grunde das Gleiche.

2

Wenn Sie diese switch-Anweisung sehen, denken Sie Polymorphismus. Dieser Entwurf kann nur durch Modifikation erweitert werden. Ich würde es so wiederholen, dass ich neues Verhalten hinzufügen könnte, indem ich Klassen hinzufüge. Genau darum geht es beim offenen/geschlossenen Prinzip.

1

Interessant, dass Sie die Abhängigkeitsinjektion auf ein C++ - Projekt anwenden; Es wurde anderswo gemacht, eine schnelle Google-Suche findet ein Google-Code-Projekt Autumn Framework.

Aber die Antwort von Tvanfosson ist, was ich vorschlagen würde, zuerst zu versuchen, bevor ein neues Rahmenwerk angenommen wird.