2017-10-10 9 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; 

} 

I는이처럼 리팩토링했다 방법 : 나는 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>) 사이에 무엇인가를 동작하는

인터페이스과 같이 선언 나중에 각 구현에 대해 정의하는 유형입니다.

도메인 기반 디자인에 대한 서적은 서비스가 싱글 톤임을 정의하므로 대부분의 경우 같은 서비스의 인스턴스를 여러 개 만들면 안됩니다.

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); 
등의 작업을 수행 할 수있는 표준 형식을 사용하기 시작하면