使用策略模式的Java Emailer

使用策略模式的Java Emailer,java,oop,design-patterns,strategy-pattern,Java,Oop,Design Patterns,Strategy Pattern,更新:又增加了一个问题(问题4) 大家好 我正在为自己构建一个自定义电子邮件实用程序。现在,为了遵守单一责任原则,我希望有以下类:MailerSender、MailProvider和EmailObject。MailSender更像是一个委托人,请在下面查看: public class MailSender { private IMailProvider mailProvider; public void setMailProvider (IMailProvider provid

更新:又增加了一个问题(问题4)

大家好

我正在为自己构建一个自定义电子邮件实用程序。现在,为了遵守单一责任原则,我希望有以下类: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:

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.这个设计好吗?邮件提供者知道EmailObject有意义吗?
3.如果我以后有一个需要附件的新EmailObject呢?

4.客户端代码现在需要在创建MailSender之前获取特定的MailProvider。。。这有意义吗?

好的,让我们来看看你的问题

1) 模糊地说,是的。你可以说你有“算法”或“策略”,你可以在它们之间选择。然而,我更喜欢将策略模式看作与算法相关的东西。例如,获取搜索结果的不同方法。在这里,您要处理的是不同的代理,您可以将发送电子邮件的角色委托给这些代理。这是一种常见的设计,但我不确定我是否一定会称之为策略。无论哪种方式,设计模式都是为了帮助您思考,而不是将您锁定在特定的名称上

2) 我认为这个设计是合理的。我会使用接口而不是实际的类,尤其是对于EMailObject。此外,应该有一个工厂的电子邮件对象,而不仅仅是新的。很可能每个提供商都会提供自己的“电子邮件对象”,其中包括包的详细信息。您发送的是内容,而不是“信封”


3) 这是使用接口而不是类的另一个很好的理由。您可能希望包含元数据和潜在附件的getter/setter,因为它们是您域(电子邮件)的合法部分。

我认为这里最重要的问题是:

  • 您能在不发送实际电子邮件的情况下测试组件吗?是的:

    MailSender sender = new MailSender(new FakeMailProvider());
    sender.send(new EmailObject());
    
  • 你能在不使用应用程序其余部分的情况下测试你的电子邮件提供商吗?是的:

    SMTPMailProvider provider = new SMTPMailProvider();
    provider.send(new EmailObject());
    
  • 您已成功地将提供程序与发件人解耦


    编辑:第四季度。在发送EmailObject之前,客户端需要将特定的MailProvider传递给MailSender。这句话可以转化为这样的话:“客户要求电子邮件服务发送电子邮件,传递电子邮件数据并选择传输方式(发送电子邮件的一种方式)”。我认为这是可以的,但是如果您不想每次都指定传输,您可以将其更改为“…服务然后使用配置的传输发送电子邮件”,并将提供程序实例化移动到配置中

    对于这句话+1:“无论哪种方式,设计模式都是为了帮助你思考,而不是把你锁定在一个特定的名字上。”我花了一段时间才明白:^)我正在试图找到一个好方法来做到这一点。MailerSender是一个EmailObject接口,而不是一个具体的类,提供者如何“获取”信息?接口将为具体类中的信息提供一个契约,但是当我使用添加的信息创建一个新对象时会发生什么呢?在基本电子邮件(收件人、发件人、抄送、主题、正文)与带有附件(字节[]数据)的电子邮件的情况下,您必须确定每个提供商都熟悉的电子邮件内容,并在界面中提供获取者。提供商通常只能处理电子邮件,因此您需要在电子邮件中输入您需要的所有内容。@bedwyr:谢谢。每当我被要求背诵GOF的书时,我仍然试图在求职面试中传达这一信息。EMailObject工厂会是什么样子?为什么我需要它?为什么客户端不能只编写一个“新”的代码,并使用变体来填充对象?您认为客户端必须将邮件提供者传递给邮件发送者有意义吗?有没有办法使用工厂或构建器模式来解决这个问题?恭喜你,你刚刚意识到需要依赖注入!别以为我是在开你的玩笑,这真的像是程序员的下一关:@bbmud酷!但是如果没有DI/IoC框架,您将如何处理这个问题呢?在MailSender类上定义第二个空构造函数,它使用MailProvider的默认版本的新实例(所谓的poor's man依赖项注入)调用第一个构造函数。