2017-10-10 14 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(){} 
} 

今私の質問です、電子メールを構築するため)buildEmail(に必要なオブジェクトを渡すの最良の方法はどのようになるか、別のオブジェクト(例えばReportRequestまたはaccountInfoのような他のオブジェクト)を利用しますか?

私がここで行ったのは、別のメソッドを作成し、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>)の間にあるもので、それはプレースホルダとして機能します各実装で後で定義する型のために。

Domain Driven Designに関する書籍では、サービスがシングルトンであると定義されているため、ほとんどの場合、同じサービスのインスタンスを複数作成しないでください。

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); 
のようなものを行うことができます
関連する問題