2017-10-10 59 views
0

在報告模塊中,有一個電子郵件服務需要重構,因此我可以將其用作通用郵件服務。實際上,當他們想重置密碼時,我有要求給用戶發送電子郵件,這是重構的主要原因。將類方法重構爲java中的接口

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; 

} 

的方式我不得不重構這是這樣的:

我創建具有buildEmail()方法調用EmailService的接口。我在想,實現這個目標的任何一個類將有不同的方式來構建/構建它的電子郵件。

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()如何訪問構建電子郵件時需要的特定對象。

回答

3

泛型可以幫助你解決這個問題。

聲明界面,如下所示:

interface EmailService<T> { 
    Email buildEmail(T t); 
} 

和你的實現是這樣的:

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

的「仿製藥」的部分是什麼,是人字形(<T>)之間,它作爲一個佔位符對於您稍後爲每個實現定義的類型。

有關域驅動設計的書定義了服務是單例,所以在大多數情況下,您不應該創建同一服務的多個實例。

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);