2009-05-17 3 views
6

ОБНОВЛЕНО: Добавлен еще один вопрос (вопрос № 4).Emailer в Java с использованием шаблона стратегии

Привет всем,

Я строю себе обычай отправки по электронной почте утилиты. Теперь, чтобы подчиняться принципу единой ответственности, я хочу иметь следующие классы: MailerSender, MailProvider и EmailObject. MailSender больше делегата, проверить его ниже:

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

MailSender требует поставщика услуг электронной почты IMailProvider, что делает работу отправки по электронной почте. Найдите ниже:

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

Я определил несколько стратегий выше, но его можно расширить до любого числа. Поскольку MailSender может в любой момент изменить свой провайдер, он эффективно реализует стратегический шаблон?

EmailObject является POJO, содержащий relavent информацию по электронной почте:

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

    // setters and getters for all 
} 

Клиентский код будет выглядеть следующим образом:

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

Мои вопросы:

1. Имею ли я реализовать шаблон стратегии ?
2. Является ли этот дизайн хорошим? Имеет ли смысл MailProvider знать об элементе EmailObject?
3. Что делать, если у меня появился новый модуль EmailObject позже, если требуется вложение?
4. Клиентский код теперь должен приобрести определенный MailProvider перед созданием MailSender ... это имеет смысл?

ответ

7

Хорошо, давайте рассмотрим ваши вопросы.

1) Смутно, да. Вы можете утверждать, что у вас есть «алгоритмы» или «стратегии», и вы можете выбирать между ними. Тем не менее, я предпочитаю думать о шаблоне стратегии как о чем-то, что имеет отношение к алгоритмам. Например, различные способы получения результата поиска. Здесь вы имеете дело с различными агентами, которым вы делегируете роль отправки электронной почты. Это общий дизайн, но я не уверен, что обязательно буду называть его стратегией. В любом случае, шаблоны дизайна предназначены для того, чтобы вы могли подумать, а не запирать вас на определенное имя.

2) Я думаю, что дизайн разумный. Я бы использовал интерфейсы, а не фактические классы, особенно для EMailObject. Кроме того, должен быть завод для объекта электронной почты, а не только новый. Также очень вероятно, что каждый поставщик предоставит собственный «объект электронной почты», который включает в себя детали пакета. Вы отправляете содержимое, а не «конверт».

3) Это еще одна веская причина использовать интерфейсы, а не класс. И вы можете включить геттеры/сеттеры для метаданных и потенциально вложений, поскольку они являются законной частью вашего домена (электронной почты).

+3

+1 для этого утверждения: «В любом случае, шаблоны проектирования призваны помочь вам думать, а не блокировать вас определенным именем». Мне потребовалось некоторое время, чтобы узнать, что: ^) – bedwyr

+0

Я пытаюсь найти хороший способ сделать это. MailerSender получает интерфейс EmailObject вместо конкретного класса, как провайдер «получает» информацию? Интерфейс предоставит контракт для информации в конкретном классе, но что произойдет, когда я создам новый объект с информацией _added_? В случае основного электронного письма (в, из, cc, subject, body) по сравнению с электронным письмом с вложением (байт [])? – djunforgetable

+0

Вы должны определить, что такое электронная почта, с которой каждый поставщик знаком и предлагает геттеры в интерфейсе. Поставщиков, как правило, можно ожидать, что они будут иметь дело с электронными письмами, поэтому вам нужно будет поместить в электронное письмо все, что вам нужно. – Uri

0

Наиболее важные вопросы здесь, на мой взгляд:

  1. Вы можете протестировать компонент без отправки фактических сообщений электронной почты?Да:

    MailSender sender = new MailSender(new FakeMailProvider()); 
    sender.send(new EmailObject()); 
    
  2. Можете ли вы протестировать поставщиков электронной почты без остальной части приложения? Да:

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

Вы успешно разъединены поставщиков от отправителей.

EDIT: Q4. Клиент должен передать конкретный MailProvider в MailSender перед отправкой EmailObject. Этот оператор можно преобразовать в нечто вроде этого: «клиент просит службу электронной почты отправлять электронную почту, передавать данные электронной почты и выбирать транспорт (способ отправки электронной почты)». Я думаю, что все в порядке, но если вы не хотите указывать транспорт каждый раз, вы можете изменить его на «... служба затем отправляет электронное письмо с использованием сконфигурированного транспорта» и переводит экземпляр поставщика в конфигурацию.

+1

Как вы думаете, имеет ли смысл, чтобы клиент должен был передать MailProvider в MailSender? Есть ли способ обойти это, используя шаблон фабрики или строителя? – djunforgetable

+0

Поздравляем, вы только что осознали необходимость инъекции зависимостей! Не думайте, что я пытаюсь вас отшутить здесь, это действительно похоже на следующий уровень для программиста: http://codebetter.com/blogs/jeremy.miller/archive/2008/11/11/evolution- of-a-developer-in-regards-to-di-ioc.aspx – bbmud

+0

@bbmud cool! но как бы вы могли работать без рамки DI/IoC? – djunforgetable

Смежные вопросы