2009-05-17 15 views
6

ACTUALIZADO: Se ha agregado una pregunta más (Pregunta 4).Emailer en Java con el Patrón de estrategia

Hola a todos,

Estoy construyendo mi mismo una costumbre enviando un correo electrónico de servicios públicos. Ahora, para obedecer el Principio de Responsabilidad Individual, quiero tener las siguientes clases: MailerSender, MailProvider y EmailObject. El MailSender es más de un delegado, echa un vistazo a continuación:

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

la MailSender requiere un proveedor de correo electrónico IMailProvider que hace el trabajo de enviar el correo electrónico. Encontrar a continuación:

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

he definido algunas estrategias anteriormente, pero puede extenderse a cualquier número. Dado que MailSender puede cambiar su proveedor en cualquier momento, efectivamente implementa el patrón de estrategia ¿verdad?

El EmailObject es un POJO que contiene la información de correo electrónico relavent:

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

    // setters and getters for all 
} 

El código de cliente será el siguiente aspecto:

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

Mis preguntas son:

1. Tener he implementado el patrón de estrategia ?
2. ¿Es este diseño bueno? ¿Tiene sentido que un proveedor de correo tenga conocimiento de un EmailObject?
3. ¿Qué pasa si tengo un nuevo EmailObject más tarde que requiere un archivo adjunto?
4. El código del cliente ahora necesita adquirir un MailProvider específico antes de crear un MailSender ... ¿tiene sentido esto?

Respuesta

7

Bien, repasemos sus preguntas.

1) Vagamente, sí. Podría argumentar que tiene "algoritmos" o "estrategias" y que puede elegir entre ellos. Sin embargo, prefiero pensar en el patrón de estrategia como algo relevante para los algoritmos. Por ejemplo, diferentes formas de obtener un resultado de búsqueda. Aquí se trata de diferentes agentes a los que delega la función de enviar correos electrónicos. Ese es un diseño común, pero no estoy seguro de que necesariamente lo llame estrategia. De cualquier forma, los patrones de diseño están destinados a ayudarlo a pensar, no a bloquearlo con un nombre específico.

2) Creo que el diseño es razonable. Usaría interfaces en lugar de clases reales, especialmente para el objeto EMailObject. Además, debe haber una fábrica para el objeto de correo electrónico, no solo nuevos. También es muy probable que cada proveedor proporcione su propio "objeto de correo electrónico" que incluya detalles del paquete. Usted está enviando los contenidos, no el "sobre".

3) Esa es otra buena razón para utilizar interfaces en lugar de una clase. Y es posible que desee incluir getters/setters para metadatos y potencialmente archivos adjuntos porque son una parte legítima de su dominio (un correo electrónico).

+3

+1 para esta afirmación: "De cualquier forma, los patrones de diseño están destinados a ayudarlo a pensar, no a bloquearlo con un nombre específico". Me tomó un tiempo aprender que: ^) – bedwyr

+0

Estoy tratando de encontrar una buena manera de hacer esto. El MailerSender obtiene una interfaz de EmailObject en lugar de una clase concreta, ¿cómo puede el proveedor "obtener" la información? La interfaz proporcionará un contrato para la información en la clase concreta, pero ¿qué sucederá cuando creo un nuevo objeto con _added_ información? En el caso de un correo electrónico básico (a, desde, cc, asunto, cuerpo) versus un correo electrónico con datos adjuntos (byte [])? – djunforgetable

+0

Debe determinar qué correo electrónico tiene cada proveedor con el que esté familiarizado y ofrecer getters en la interfaz. Por lo general, se espera que los proveedores solo se ocupen de los correos electrónicos, por lo que debe ingresar todo lo que necesite en el correo electrónico. – Uri

0

Las preguntas más importantes aquí son en mi opinión:

  1. se puede probar su componente sin necesidad de enviar correos electrónicos reales?Sí:

    MailSender sender = new MailSender(new FakeMailProvider()); 
    sender.send(new EmailObject()); 
    
  2. se puede probar sus proveedores de correo electrónico sin el resto de la aplicación? Sí:

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

Usted ha desacoplado con éxito los proveedores de los remitentes.

EDITAR: Q4. El cliente debe pasar el MailProvider específico al MailSender antes de enviar EmailObject. Esta afirmación puede transformarse en algo como esto: "el cliente le pide al servicio de correo electrónico que envíe el correo electrónico, que pase datos de correo electrónico y elija un transporte (una forma de enviar un correo electrónico)". Creo que está bien, pero si no desea especificar el transporte cada vez, puede cambiarlo a "... el servicio luego envía el correo electrónico utilizando el transporte configurado" y mover la creación de instancias del proveedor a la configuración.

+1

¿Cree que tiene sentido que el cliente tenga que pasar un MailProvider al MailSender? ¿Hay alguna forma de evitar esto usando un patrón de fábrica o de constructor? – djunforgetable

+0

¡Enhorabuena, acaba de darse cuenta de la necesidad de una Inyección de Dependencia! No crea que estoy tratando de bromear con usted aquí, esto es realmente como un siguiente nivel para un programador: http://codebetter.com/blogs/jeremy.miller/archive/2008/11/11/evolution- of-a-developer-in-regards-to-di-ioc.aspx – bbmud

+0

@bbmud ¡genial! pero, ¿cómo trabajarías esto sin un marco DI/IoC? – djunforgetable

Cuestiones relacionadas