반응형
데코레이터 패턴 (Decorator Pattern) 이란?
기존에 있는 코드를 변경하지 않고 부가적인 기능을 추가하는 패턴이다.
데코레이터 사용 전
Comment 를 관리하는 CommentService 는 아래와 같으며 addComment 는 Comment 를 출력하는 메서드이다.
public class CommentService {
public void addComment(String comment) {
System.out.println(comment);
}
}
SpamFiltering 은 http 프로토콜을 받기 싫다면 그에 맞는 기능을 추가해야한다.
해당 기능은 아래와 같이 SpamFilteringCommentService로 구현할 수 있다
public class SpamFilteringCommentService extends CommentService {
@Override
public void addComment(String comment) {
boolean isSpam = isSpam(comment);
if (!isSpam) {
super.addComment(comment);
}
}
private boolean isSpam(String comment) {
return comment.contains("http");
}
}
만약, "..." 과 특수기호는 관리하고 싶지 않다면 그에 맞는 기능을 추가해야한다.
해당 기능은 아래와같이 TrimmingCommentService 로 구현할 수 있다.
public class TrimmingCommentService extends CommentService {
@Override
public void addComment(String comment) {
super.addComment(trim(comment));
}
private String trim(String comment) {
return comment.replace("...", "");
}
}
이를 사용하기 위해 Client는 아래와 같이 의존관계만 변경해주면된다.
public class Client {
private CommentService commentService;
public Client(CommentService commentService) {
this.commentService = commentService;
}
private void writeComment(String comment) {
commentService.addComment(comment);
}
public static void main(String[] args) {
Client client = new Client(new SpamFilteringCommentService());
client.writeComment("오징어게임");
client.writeComment("보는게 하는거 보다 재밌을 수가 없지...");
client.writeComment("http://whiteship.me");
}
}
문제발생
- SpamService , TrimService 모두 사용하려면 이 두 코드가 포함된 새로운 CommentService 를 만들어야 한다.
- 아니면, 새로운 CommentService 를 만들어 이 둘을 이중 상속받아야 한다.
이를 데코레이터 패턴을 적용하여 해결해보자.
데코레이터 패턴 적용 후
먼저 공통된 기본 기능을 가진 CommentService 인터페이스
그리고 그 기본 기능을 구현하는 DefaultCommentService 는 아래와 같다.
Interface CommentService 생성
public interface CommentService {
void addComment(String comment);
}
DefaultCommentService
public class DefaultCommentService implements CommentService{
@Override
public void addComment(String comment) {
System.out.println(comment);
}
}
CommentDecorator
public class CommentDecorator implements CommentService{
private CommentService commentService;
public CommentDecorator(CommentService commentService){
this.commentService = commentService;
}
@Override
public void addComment(String comment) {
commentService.addComment(comment);
}
}
SpamFilteringCommentDecorator
public class SpamFilteringCommentDecorator extends CommentDecorator{
public SpamFilteringCommentDecorator(CommentService commentService) {
super ( commentService );
}
@Override
public void addComment(String comment) {
if (isNotSpam(comment)){
super.addComment ( comment );
}
}
private boolean isNotSpam(String comment) {
return comment.contains("http");
}
}
TrimmingCommentDecorator
public class TrimmingCommentDecorator extends CommentDecorator{
public TrimmingCommentDecorator(CommentService commentService) {
super (commentService);
}
@Override
public void addComment(String comment) {
super.addComment(trim(comment));
}
private String trim(String comment) {
return comment.replace("...","");
}
}
client
public class Client {
private CommentService commentService;
public Client(CommentService commentService){
this.commentService = commentService;
}
public void writeComment(String comment) {
commentService.addComment(comment);
}
}
App
public class App {
private static boolean enabledSpamFilter = true;
private static boolean enabledTrimming = true;
public static void main(String[] args) {
CommentService commentService = new DefaultCommentService ();
if(enabledSpamFilter) {
commentService = new SpamFilteringCommentDecorator(commentService);
}
if(enabledTrimming) {
commentService = new TrimmingCommentDecorator(commentService);
}
Client client = new Client(commentService);
client.writeComment("오징어게임");
client.writeComment("보는게 하는거 보다 재밌을 수가 없지");
client.writeComment("http://whiteship.me");
}
}
위와 같이 데코레이터를 사용하면 단일 책임 원칙, 개방 폐쇄 원칙을 지키면서 새로운 클래스를 만들지 않고도 기존 기능을 조합할 수 있다. 하지만 기능이 늘어날수록 코드가 복잡해질수가 있다.
장점
- 새로운 클래스를 만들지 않고 기존 기능을 조합할 수 있다
- 컴파일 타임이 아닌 런타임에 동적으로 기능을 변경할 수 있다
단점
- 데코레이터를 조합하는 코드가 복잡할 수 있다
참고
'디자인패턴' 카테고리의 다른 글
플라이웨이턴 패턴 (Flyweight Pattern) (0) | 2022.08.15 |
---|---|
퍼사드 패턴(Facade Pattern) (0) | 2022.08.14 |
컴포짓(composite) 패턴 (0) | 2022.07.30 |
브릿지(Bridge)패턴 (0) | 2022.07.20 |
프로토타입(Prototype) 패턴 (0) | 2022.07.08 |