在java中将类方法重构为接口

时间:2017-10-10 06:26:58

标签: java design-patterns refactoring

在报告模块中,有一个我想要重构的电子邮件服务,因此我可以将其用作通用电子邮件服务。实际上,我需要在用户重置密码时向用户发送电子邮件,这是重构的主要原因。

public class EmailService{

    public Email buildEmail(ReportRequest reportRequest){
    //build email using ReportRequest object here
    }

}

@Builder
@Getter
@Setter
@AllArgsConstructor
public class Email implements Serializable {
    private String subject;
    private String text;
    private String recipientEmail;
    private String senderEmail;

}

我重构的方式是这样的:

我创建了一个名为EmailService的接口,它有一个buildEmail()方法。我在想,实现这一目标的任何一个类都有不同的构建/构建其电子邮件的方式。

public interface EmailService{
    public Email buildEmail();
}

public class ReportEmailService implements EmailService{
   public Email buildEmail(){}
}

public class PasswordEmailService implements EmailService{
   public Email buildEmail(){}
}

我现在的问题是,由于构建电子邮件将使用不同的对象(例如ReportRequest或其他对象,如AccountInfo),将所需对象传递到buildEmail()的最佳方法是什么?

我在这里做的是创建另一个方法并为buildEmail()中使用的所需对象创建一个类变量。

基本上,现在它看起来像这样:

public class ReportEmailService implements EmailService{
   private ReportRequest reportRequest;

   public void sendEmail(ReportRequest reportRequest){
       this.reportRequest = reportRequest;
       Email email = buildEmail();
   }

   public Email buildEmail(){
       #build email now using the report request object. 
   }
}

 public class PasswordResetEmailService implements EmailService{
   private AccountInfo accountInfo;

   public void sendEmail(AccountInfo accountInfo){
       this.accountInfo= accountInfo;
       Email email = buildEmail();
   }

   public Email buildEmail(){
       #build email now using the account info object. 
   }
}

我觉得我的做法有点尴尬。我可能在设计模式和重构方面错过了一些基本的东西,那么重构这个可能是最好的方法呢?或者buildEmail()如何能够访问构建电子邮件时所需的特定对象。

2 个答案:

答案 0 :(得分:3)

泛型可以帮助您解决此问题。

声明接口如下:

class ReportEmailService<ReportRequest> implements EmailService {
    Email buildEmail(ReportRequest req) {
        ...
    }
}

以这种方式实施:

<T>

&#34;泛型&#34; part是V形符号之间的内容(MethodInvocation: MethodName ( [ArgumentList] ) TypeName . [TypeArguments] Identifier ( [ArgumentList] ) ExpressionName . [TypeArguments] Identifier ( [ArgumentList] ) Primary . [TypeArguments] Identifier ( [ArgumentList] ) super . [TypeArguments] Identifier ( [ArgumentList] ) TypeName . super . [TypeArguments] Identifier ( [ArgumentList] ) ArgumentList: Expression {, Expression} ),它作为您稍后为每个实现定义的类型的占位符。

有关域驱动设计的书籍定义服务是单例,因此在大多数情况下,您不应该创建同一服务的多个实例。

答案 1 :(得分:2)

您可以实现多个电子邮件服务,也可以委托参数。

interface EmailService {
    boolean send(EmailFactory arg)

    interface EmailFactory {
        Email buildEmail();
    }
}

然后,您的ReportRequestAccountInfo类可以实现EmailFactory,甚至更好,您创建了一个适配器类,它知道如何为每种类型buildEmail

class ReportRequestEmailFactory implements EmailFactory {
    private ReportRequest report;
    public Email buildEmail() {
        return ...
    }
}

class AccountInfoEmailFactory implements EmailFactory {
    private AccountInfo account;
    public Email buildEmail() {
        return ...
    }
}

通过这种方式,您可以实现一个只知道如何发送电子邮件的EmailService。并且您为要作为电子邮件发送的每种类型的事物实现特定的包装器/适配器。

这也可以轻松扩展,以允许针对不同域类的不同类型的电子邮件,例如FullDetailsAccountInfoEmailFactorySummaryAccountInfoEmailFactory

如果您开始使用标准类型

,也许可以获得奖励积分
class EmailService implements Consumer<Email> {
    public void accept(Email email) {
        // TODO: send email
    }
}
class AccountInfoEmailTransformer implements Function<AccountInfo,Email> {
    public Email apply(AccountInfo t) {
        // TODO: transform AccountInfo to Email
        return ...
    }
}

然后你可以做像

这样的事情
EmailService emailer = ...
AccountInfoEmailFunction transformer = ...

List<AccountInfo> accounts = ...

accounts.stream().map(transformer).forEach(emailer);