본문 바로가기
java

Design Patterns - Decorator

by 쭈꾸마뇽 2021. 12. 4.

기존 코드를 변경하지 않고 부가 기능을 추가하는 패턴

상속이 아닌 위임을 사용해서 보다 유연하게(런타임에) 부가 기능을 추가하는 것도 가능하다

public class Client {

    private CommentService commentService;

    public Client(CommentService commentService) {
        this.commentService = commentService;
    }

    public void writeComment(String comment) {
        commentService.addComment(comment);
    }
}

먼저 App에서 사용할 Client를 만들어 준다.

public interface CommentService {

    void addComment(String comment);
}

Client에서 사용할 CommentService를 만들어서 Client는 이 인터페이스를 호출하여 원하는 기능 수행을 한다.

public class DefaultCommentService implements CommentService {
    @Override
    public void addComment(String comment) {
        System.out.println(comment);
    }
}

CommentService 인터페이스를 상속받는 기본 구현 클래스를 만들어준다.  이 클래스는 입력받은 문자열을 출력한다.

public class CommentDecorator implements CommentService {

    private CommentService commentService;

    public CommentDecorator(CommentService commentService) {
        this.commentService = commentService;
    }

    @Override
    public void addComment(String comment) {
        commentService.addComment(comment);
    }
}

CommentDecorator는 CommentService를 구현하는데 이때 직접적인 기능 수행을 하지 않고 CommentService를 인스턴스 변수로 갖고 그 변수의 함수를 호출한다.

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");
    }
}
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("...", "");
    }
}

CommentDecorator를 상속받는 추가기능 구현 클래스들을 구현한다.

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");
    }
}

App에서는 맨처음 DefaultCommentService를 만들어 준다.  그다음 추가 기능구현을 한 클래스들의 객체를 생성하는데 이때 DefaultCommentService 객체를 매개변수로 넣어준다.  이렇게 되면 SpamFilteringCommentDecorator는 멤버변수로 DefaultCommentService를 갖게 되고 내부에서 로직을 수행한 다음 DefaultCommentService의 addComment 함수를 호출하게 된다.

 

그다음 TrimmingCommentDecorator의 매개변수로 SpamFilteringCommentDecorator를 넣어주게 되면 멤버변수로 SpamFilteringCommentDecorator를 갖게 되어 내부로직 수행 후 SpamFilteringCommentDecorator의 addComment 함수를 호출한다.

 

그러면 TrimmingCommentDecorator.addComment() -> SpamFilteringCommentDecorator.addComment() -> DefaultCommentService.addComment() 순서대로 호출이 되어 추가기능을 넣을 수 있다.

  • 장점
    • 새로운 클래스를 만들지 않고 기존 기능을 조합할 수 있다
    • 컴파일 타임이 아닌 런타임에 동적으로 기능을 변경할 수 있다
  • 단점
    • 데코레이터를 조합하는 코드가 복잡할 수 있다

 

 

코딩으로 학습하는 GoF의 디자인 패턴 - 인프런 | 강의

디자인 패턴을 알고 있다면 스프링 뿐 아니라 여러 다양한 기술 및 프로그래밍 언어도 보다 쉽게 학습할 수 있습니다. 또한, 보다 유연하고 재사용성이 뛰어난 객체 지향 소프트웨어를 개발할

www.inflearn.com

 

'java' 카테고리의 다른 글

Design Patterns - Flyweight  (0) 2021.12.21
Design Patterns - Facade  (0) 2021.12.10
Design Patterns - Composite  (0) 2021.11.29
Design Patterns - Bridge  (0) 2021.11.28
Design Patterns - Adapter  (0) 2021.11.24

댓글