2009-05-17 5 views
6

AKTUALISIERT: Eine weitere Frage hinzugefügt (Frage # 4).Emailer in Java mit Strategie Muster

Hallo,

Ich baue mir eine eigene E-Mail-Programm. Nun, um das Prinzip der einfachen Verantwortlichkeit zu erfüllen, möchte ich die folgenden Klassen haben: MailerSender, MailProvider und EmailObject. Der Mailsender mehr eines Delegierten, überprüfen Sie es unten aus:

public class MailSender { 
    private IMailProvider mailProvider; 

    public void setMailProvider (IMailProvider provider) { 
     this.mailProvider = provider; 
    } 

    // option to set it up during construction 
    public MailSender (IMailProvider provider) { 
     this.mailProvider = provider; 
    } 

    public void sendEmail(EmailObject obj) { 
     if(mailProvider == null) 
      throw new RuntimeException("Need a mail provider to send email."); 

     try { 
      mailProvider.send(obj); 
     } catch (Exception e) { 
      // do something here 
     } 
    } 
} 

Der Mailsender erfordert eine IMailProvider E-Mail-Anbieter, der die Arbeit des Sendens der E-Mail der Fall ist. Finden Sie es unter:

public interface IMailProvider { 
    public void sendEmail(EmailObject obj); 
} 

public class SMTPEmailProvider implements IMailProvider { 
    public void sendEmail(EmailObject obj) { 
     // use SMTP to send email using passed-in config 
    } 
} 

public class JMSEmailProvider implements IMailProvider { 
    public void sendEmail(EmailObject obj) { 
     // push emails to JMS queue to be picked up by another thread 
    } 
} 

Ich habe ein paar Strategien oben definiert, aber es kann zu jeder Zahl erweitert werden. Da der MailSender seinen Provider jederzeit wechseln kann, implementiert er das Strategie-Pattern richtig?

Die EmailObject ist ein POJO relavent E-Mail-Informationen enthält:

public class EmailObject { 
    private String to; 
    private String from; 
    private String cc; 
    private String subject; 
    private String body; 

    // setters and getters for all 
} 

Client-Code wird dann wie folgt aussehen:

MailSender sender = new MailSender(new SMTPMailProvider()); 
sender.send(new EmailObject()); 
sender.setMailProvider(new JMSMailProvider()); 
sender.send(new EmailObject()); 

Meine Fragen sind:

1. Habe ich das Strategy-Muster umgesetzt ?
2. Ist dieses Design gut? Ist es für einen MailProvider sinnvoll, auf ein EmailObject zu achten?
3. Was wäre, wenn ich später ein neues EmailObject hätte, das einen Anhang benötigt?
4. Der Client-Code muss jetzt einen bestimmten MailProvider erhalten, bevor er einen MailSender erstellt ... macht das Sinn?

Antwort

7

Ok, lass uns deine Fragen durchgehen.

1) Vage, ja. Sie könnten argumentieren, dass Sie "Algorithmen" oder "Strategien" haben und dass Sie zwischen ihnen wählen können. Ich bevorzuge es jedoch, das Strategie-Muster als etwas zu betrachten, das für Algorithmen relevant ist. Zum Beispiel verschiedene Möglichkeiten, um ein Suchergebnis zu erhalten. Hier haben Sie es mit verschiedenen Agenten zu tun, an die Sie die Rolle des E-Mail-Versands delegieren. Das ist ein gängiges Design, aber ich bin mir nicht sicher, ob ich es unbedingt Strategie nennen würde. Wie auch immer, Design Patterns sollen Ihnen helfen, zu denken, nicht um Sie an einen bestimmten Namen zu sperren.

2) Ich denke, das Design ist vernünftig. Ich würde Schnittstellen anstelle von tatsächlichen Klassen verwenden, insbesondere für das EMailObject. Außerdem sollte es eine Factory für E-Mail-Objekte geben, die man nicht einfach neu anlegt. Es ist auch sehr wahrscheinlich, dass jeder Anbieter sein eigenes "E-Mail-Objekt" bereitstellt, das Paketdetails enthält. Sie senden den Inhalt, nicht den "Umschlag".

3) Das ist ein weiterer guter Grund, Schnittstellen statt einer Klasse zu verwenden. Und vielleicht möchten Sie Getter/Setter für Metadaten und potentielle Anhänge hinzufügen, weil sie ein legitimer Teil Ihrer Domain (eine E-Mail) sind.

+3

+1 für diese Aussage: "Wie auch immer, Entwurfsmuster sollen Ihnen helfen zu denken, nicht Sie an einen bestimmten Namen zu sperren." Ich brauchte eine Weile, um das zu lernen: ^) – bedwyr

+0

Ich versuche, einen guten Weg zu finden, dies zu tun. Der MailerSender bekommt eine EmailObject-Schnittstelle statt einer konkreten Klasse, wie kommt der Provider auf die Informationen? Die Schnittstelle liefert einen Vertrag für die Informationen in der konkreten Klasse, aber was passiert, wenn ich ein neues Objekt mit _added_ Informationen erstelle? Im Falle einer grundlegenden E-Mail (an, von, cc, Betreff, Körper) im Vergleich zu einer E-Mail mit einem Anhang (Byte [] Daten)? – djunforgetable

+0

Sie müssen feststellen, was eine E-Mail hat, mit der jeder Anbieter vertraut ist, und Getter in der Schnittstelle anbieten. Von den Providern kann im Allgemeinen nur erwartet werden, dass sie mit E-Mails umgehen, also müssen Sie in die E-Mail alles eintragen, was Sie benötigen. – Uri

0

Die wichtigsten Fragen hier sind meiner Meinung nach:

  1. Können Sie Ihre Komponente testen, ohne dass tatsächliche E-Mails?Ja:

    MailSender sender = new MailSender(new FakeMailProvider()); 
    sender.send(new EmailObject()); 
    
  2. Können Sie Ihre E-Mail-Anbieter, ohne den Rest der Anwendung testen? Ja:

    SMTPMailProvider provider = new SMTPMailProvider(); 
    provider.send(new EmailObject()); 
    

Sie haben erfolgreich Anbieter von Absendern entkoppelt.

BEARBEITEN: Q4. Der Client muss den bestimmten MailProvider an den MailSender übergeben, bevor er EmailObject sendet. Diese Anweisung kann in etwa so aussehen: "Der Client fordert den E-Mail-Dienst auf, die E-Mail zu senden, E-Mail-Daten weiterzuleiten und einen Transport auszuwählen (eine Möglichkeit, eine E-Mail zu senden)." Ich denke, es ist in Ordnung, aber wenn Sie den Transport nicht jedes Mal angeben möchten, können Sie ihn in "... der Dienst sendet dann die E-Mail mit dem konfigurierten Transport" ändern und die Provider-Instanziierung in die Konfiguration verschieben.

+1

Findest du es sinnvoll, dass der Client einen MailProvider an den MailSender übergeben muss? Gibt es eine Möglichkeit, dies mithilfe eines Fabrik- oder Buildermusters zu umgehen? – djunforgetable

+0

Herzlichen Glückwunsch, Sie haben gerade eine Notwendigkeit für Dependency Injection erkannt! Ich glaube nicht, dass ich hier einen Witz von dir mache, das ist wirklich wie ein nächstes Level für einen Programmierer: http://codebetter.com/blogs/jeremy.miller/archive/2008/11/11/evolution- von-einem-Entwickler-in-Bezug-zu-di-ioc.aspx – bbmud

+0

@bbmud cool! Aber wie würdest du ohne DI/IoC-Framework arbeiten? – djunforgetable