어떤 서브시스템의 일련의 인터페이스에 대한 통합된 인터페이스를 제공합니다. 퍼사드에서 고수준 인터페이스를 정의하기 때문에 서브시스템을 더 쉽게 사용할 수 있습니다.
퍼사드 패턴 적용전의 간단한 예시 코드를 살펴보겠습니다. 이메일을 전송하는 로직입니다.
public class Client {
public static void main(String[] args) {
String to = "keesun@whiteship.me";
String from = "whiteship@whiteship.me";
String host = "127.0.0.1";
Properties properties = System.getProperties();
properties.setProperty("mail.smtp.host", host);
Session session = Session.getDefaultInstance(properties);
try {
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
message.setSubject("Test Mail from Java Program");
message.setText("message");
Transport.send(message);
} catch (MessagingException e) {
e.printStackTrace();
}
}
}
자바로 이메일을 보낼때 먼저 Properties로 smtp서버주소와 포트를 정의해야합니다. 그 다음 Properties를 가지고 Session을 생성하고 Session을 가지고 MimeMessage를 생성합니다. MimeMessage에 받는사람, 보낸사람, 제목, 본문을 채워 넣고 전송하면 됩니다. 클라이언트 코드 입장에서보면 Properties, Session, MimeMessage, MessagegingException등 다양한 의존성이 생겼습니다. 특정한 라이브러리나 프레임워크에 종속적인 코드들에 의존하는 것을 선호하지는 않습니다. 스프링 프레임워크 자체도 뭔가 의존성의 노출시키는 것을 꺼려합니다. 노출을 최소하하여 개발자가 자신이 생성한 코드에 집중하도록 인터페이스를 제공하고 있습니다. 의존성이 많다면 변경이 쉽지않고 코드를 테스트하기도 어렵습니다. 그래서 가급적이면 의존성을 최소화하고 유연성있는 코드를 생성하는것이 좋습니다. 그래서 위의 코드를 퍼사드 패턴을 적용해서 객체지향적으로 좀 더 유연성있게 코드를 변경해 보겠습니다.
앞서 이메일을 보내기위한 코드를 보면 메시지와 관련된 코드들을 메일을 보내는역할을하는 EmailSender클래스, 메일을 설정하는 EmailSettings클래스, 메시지를 담는 EmailMessage클래스로 분리시키겠습니다. 먼저 각 클래스들을 선언합니다.
public class EmailSender {
}
public class EmailSettings {
}
public class EmailMessage {
}
제일 먼저 EmailSender를 구현해보겠습니다. EmailSender클래스의 역할은 이메일을 전송하는역할입니다. 이메일을 전송하려면 메일의 설정값이 필요하기 때문에 EmailSettings를 주입받도록 하겠습니다.
public class EmailSender {
private EmailSettings emailSettings;
public EmailSender(EmailSettings emailSettings) {
this.emailSettings = emailSettings;
}
}
기존 코드의 host는 EmailSettings에 설정하도록 하고 to, from은 EmailMessage에 설정하도록 하겠습니다.
String to = "keesun@whiteship.me";
String from = "whiteship@whiteship.me";
String host = "127.0.0.1";
Properties properties = System.getProperties();
properties.setProperty("mail.smtp.host", host);
public class EmailSettings {
private String host;
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
}
public class EmailMessage {
private String from;
private String to;
private String subject;
private String text;
// getter, setter
}
public class EmailSender {
private EmailSettings emailSettings;
public EmailSender(EmailSettings emailSettings) {
this.emailSettings = emailSettings;
}
/**
* 이메일 보내는 메소드
* @param emailMessage
*/
public void sendEmail(EmailMessage emailMessage) {
Properties properties = System.getProperties();
properties.setProperty("mail.smtp.host", emailSettings.getHost());
Session session = Session.getDefaultInstance(properties);
try {
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(emailMessage.getFrom()));
message.setSubject(emailMessage.getSubject());
message.setText(emailMessage.getText());
Transport.send(message);
} catch (MessagingException e) {
e.printStackTrace();
}
}
}
public class Client {
public static void main(String[] args) {
EmailSettings emailSettings = new EmailSettings();
emailSettings.setHost("127.0.0.1");
EmailSender emailSender = new EmailSender(emailSettings);
EmailMessage emailMessage = new EmailMessage();
emailMessage.setFrom("keesun");
emailMessage.setTo("whiteship");
emailMessage.setSubject("오징어게임");
emailMessage.setText("밖은 더 지옥이더라고..");
emailSender.sendEmail(emailMessage);
}
}
EmailSettings에 host값을 설정하고 EmailSender에 주입합니다. 그리고 EmailMessage를 생성해서 EmailSender에 sendEmail메서드를 호출해서 이메일을 전송합니다. 이렇게되면 라이브러리에 대한 구체적인 의존성은 사라지지만 새로 생성한 EmailSettings, EmailSender, EmailMessage에 대한 의존성을 어쩔수 없습니다. 하지만 이전에 라이브러리를 직접 의존할때보다 코드변경은 수월해집니다. 예를 들어 이메일을 보내는 라이브러리를 다른걸로 쓰게 된다면 Client코드를 건들 필요없이 EmailSender의 내부 코드만 다른 라이브러리로 변경하면 됩니다. 그리고 테스트코드를 구현할 때 Mocking하기도 편리합니다.
이런식으로 퍼사드를 생성해서 클라이언트 코드에 의존하면 특정 라이브러리들은 또 해당 퍼사드 뒤에 어차피 의존하고 있지 않냐고 생각하실 수 있지만 만약 이메일을 보내는 곳이 여러 곳이라면 이야기가 달라집니다. 퍼사드 패턴을 적용하기 전에 이메일을 보낼때는 보내는 곳마다 Properties, Session, MimeMessage를 직접 의존해서 구현하기 때문에 설정값이 달라지면 모든 Properties가 있는 곳을 변경해야 하는 번거로움이 있습니다. 하지만 퍼사드를 사용하면 설정값들을 모아 놓았기 때문에 코드변경의 양이 상대적으로 적습니다.
결국 퍼사드 패턴은 서브 시스템에 대한 의존성을 한곳으로 모을 수 있어 복잡한 서브 시스템 의존성을 최소화 시킬 수 있습니다. 하지만 결국 퍼사드 클래스가 서브 시스템에 대한 모든 의존성을 가지게 됩니다.