데코레이터 패턴, 소개
데코레이터 패턴은 기존의 객체를 수정하지 않고 새로운 기능을 추가하거나 확장할 수 있게 만드는 패턴으로, 기존 클래스의 구조를 변경하지 않고 런 타임에 부가 기능을 추가하는 장점을 가지고 있다.
데코레이터 패턴은 다음과 같은 상황에 유용하다.
첫째로, 기존의 클래스를 변경하기 어렵고 동시에 새로운 기능이나 행동을 추가해야 할 때
둘째로, 여러 기능을 일련의 순서에 맞게 조합해서 사용해야 하는 경우 유용하다.
정리하면, 데코레이터 패턴의 핵심은 기존의 객체를 변경하지 않고도 새로운 기능을 추 할 수 있다는 점이다. 이는 객체 지향의 개방/폐쇄 원칙을 따르며, 코드의 유지 보수와 확장성을 높일 수 있다.
데코레이터 패턴, 코드
before
CommentProcessor.java
단순 String을 출력하는 기본 클래스
public class CommentProcessor {
public void addComment(String comment) {
System.out.println(comment);
}
}
TrimmingCommentProcessor.java
특정 문자를 제거하는 기능이 추가로 필요하다면 상속을 이용해서 해결할 수 있다.
public class TrimmingCommentDecorator extends CommentProcessor {
@Override
public void addComment(String comment) {
super.addComment(trim(comment));
}
private String trim(String comment) {
return comment.replace("...", "");
}
}
SpamFilteringCommentDecorator.java
spam을 제거하는 기능이 필요하다면 마찬가지로 상속을 이용할 수 있다.
public class SpamFilteringCommentDecorator extends CommentProcessor {
@Override
public void addComment(String comment) {
if (!isSpam(comment))
super.addComment(comment);
}
private boolean isSpam(String comment) {
return comment.contains("[spam]");
}
}
상속 구조의 문제는 Trimming과 SpamFiltering을 동시에 제공하는 기능이 필요하다면 또다시 새로운 클래스를 만들어야 한다. 다르게 말하면 여러 기능을 제공하는 클래스가 있을 때 선택적으로 기능을 조합해서 사용하기 어렵다고 할 수 있다. 특히 런타임에 더욱 그렇다.
after
CommentProcessor.java
모든 기능은 CommentProcessor 인터페이스를 구현함으로 써 제공한다.
public interface CommentProcessor {
void process(String comment);
}
PrintCommentProcessor.java
기본적인 기능을 제공할 구현체. 표에서는 ConcreteComponent에 해당한다.
public class PrintCommentProcessor implements CommentProcessor {
@Override
public void process(String comment) {
System.out.println(comment);
}
}
CommentDecorator.java
데코레이터 개념을 추상화한 클래스
@AllArgsConstructor
public abstract class CommentDecorator implements CommentProcessor {
private CommentProcessor delegate;
@Override
public void process(String comment) {
delegate.process(comment);
}
}
SpamFilteringCommentDecorator.java, TrimmingCommentDecorator.java
데코레이터 기능을 구현한 클래스로 CommentDecorator를 상속받는다.
public class SpamFilteringCommentDecorator extends CommentDecorator {
public SpamFilteringCommentDecorator(CommentProcessor commentProcessor) {
super(commentProcessor);
}
@Override
public void process(String comment) {
if (!isSpam(comment))
super.process(comment);
}
private boolean isSpam(String comment) {
return comment.contains("[spam]");
}
}
public class TrimmingCommentDecorator extends CommentDecorator {
public TrimmingCommentDecorator(CommentProcessor commentProcessor) {
super(commentProcessor);
}
@Override
public void process(String comment) {
super.process(trim(comment));
}
private String trim(String comment) {
return comment.replace("...", "");
}
}
예제 코드
기본적으로 제공할 기능에 동적으로 데코레이터들을 붙여가며 기능을 확장할 수 있다.
public class App {
private static boolean ENABLE_SPAM_FILTER = true;
private static boolean ENABLE_TRIM = true;
public static void main(String[] args) {
CommentProcessor commentProcessor = new PrintCommentProcessor();
if (ENABLE_SPAM_FILTER)
commentProcessor = new SpamFilteringCommentDecorator(commentProcessor);
if (ENABLE_TRIM)
commentProcessor = new TrimmingCommentDecorator(commentProcessor);
Client client = new Client(commentProcessor);
client.writeComment("hello world!..."); // ==> hello world!
client.writeComment("[spam] hello world!"); // ==> nothing
}
}
인프런의 백기선님의 강의 코딩으로 학습하는 GoF의 디자인 패턴을 참고해서 작성했습니다.
'Java > Design Pattern with Java' 카테고리의 다른 글
[구조 패턴] Chapter 10. Facade Pattern (0) | 2023.12.11 |
---|---|
[구조 패턴] Chapter 8. Composite Pattern (0) | 2023.12.10 |
[구조 패턴] Chapter 7. Bridge Pattern (0) | 2023.11.12 |
[구조 패턴] Chapter 6-2. Adapter Pattern : 패턴 적용하기 (0) | 2022.06.13 |
[구조 패턴] Chapter 6-1. Adapter Pattern : 패턴 소개 (0) | 2022.06.04 |