[객체지향설계 & 패턴] 데코레이터 패턴

2025. 5. 29. 20:22·CS/객체지향설계 & 패턴

개요

 Decorate는 '장식하다'라는 뜻의 동사인데, 이것의 파생형 Decorator는 '장식자'라는 뜻이다. 이번에 알아볼 데코레이터 패턴은 객체를 장식하는 패턴인데, 여기서 장식은 '기능을 추가한다'라고 생각하면 더 이해하기 편하다.

 

데코레이터 패턴

 데코레이터 패턴의 등장 구성 요소는 Component, ConcreteComponent, Decorator, ConcreteDecorator로 총 4가지이다. Component는 기능을 추가할 때 핵심이 되는 역할로 API만 정의하고 여기서 정의한 API는 ConcreteComponent에서 구현한다. 장식자 Decorator는 Component와 동일한 API를 가지고, Component를 인스턴스로 가진다. 구체적인 장식자 Concrete Decorator는 구체적인 Decorator로 추가할 기능을 구현한다. 예시로 데코레이터 패턴을 이해해보자.

 

 필자가 케이크를 만들어 본 경험은 없지만, 케이크를 만드는 경우를 생각해보자. 아무것도 아이싱하지 않은 케이크 시트 빵이 있고, 이 케이크 시트 빵에 생크림 / 초코 크림을 아이싱하여 아무런 것이 장식되지 않은 생크림 케이크 / 초코 케이크를 만들 수 있다. 이렇게 만든 장식 없는 생크림 / 초코 케이크를 그냥 먹을 수도 있지만, 우리는 이 케이크를 장식하기를 원한다. 케이크를 장식하는 방법에는 '포도를 더하기', '딸기를 더하기', '슈가 파우더 뿌리기', '초콜릿 올리기' 등의 여러 장식 방법이 있다. 이중에 우리는 추가하고 싶은 재료들만 생크림 / 초코 케이크에 추가만 하면 케이크를 예쁘게 꾸밀 수 있다.

 

 위 예시만 본다면, 그래서 데코레이터 패턴이 뭔데? 라고 생각이 들 것이다. 프로그래밍적 사고를 하며 위 예시를 살펴보자. 케이크는 객체이고, 구체적인 케이크 객체로 생크림 케이크 / 초코 케이크가 있는 상황이다. 이제 이 생크림 / 초코 케이크를 꾸미고 싶은데, '포도를 더하기', '딸기를 더하기' 등 여러 방식으로 케이크를 꾸미고 싶다. 즉, 케이크를 꾸미는 방식 중 우리가 원하는 것만 선택해서 케이크를 꾸미고 싶은 상황이다.

 

 위의 아무것도 아이싱하지 않은 케이크 시트 빵은 Component, 아이싱이 완료된 생크림 / 초코 케이크는 Concrete Component, 케이크를 장식하는 방식을 Topping 메소드로 처리한다고 하면, 장식하는 방법의 모음은 Decorator이다. '포도를 더하기', '딸기를 더하기'와 같은 자세한 장식 방법은 Concrete Decorator에 해당한다. 

 

여기서 케이크를 꾸미는 것을, 프로그램에 기능을 추가하는 것이라고 생각해 보자. 약간은 감이 왔다면 좋겠지만 아직 그렇지 않을 수 있다. 위 과정은, 케이크 객체을 여러 방식으로 재료를 추가하며 꾸미는 과정이다. 여기서 '케이크'를 프로그램, '여러 방식으로 재료를 꾸미기'를 '여러 기능 추가하기'라고 생각하면 이해가 될 것이다. 

 

아래 코드를 통해 데코레이터 패턴에 대해 더 뜯어보자. 

예시 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// Component
public
 interface Cake {
    String getDescription();
}

// Concrete Component 1
public class WhippedCreamCake implements Cake {
    @Override
    public String getDescription() {
        return "Whipped Cream Cake";
    }
}

// Concrete Component
2
public class ChocolateCake implements Cake {
    @Override
    public String getDescription() {
        return "Chocolate Cake";
    }
}

// Decorator
public abstract class ToppingDecorator implements Cake {
    protected Cake cake;
 
    public ToppingDecorator(Cake cake) {
        this.cake = cake;
    }
 
    public abstract String getDescription();
}

// ConcreteDecorator 1
public class GrapeTopping extends ToppingDecorator {
    public GrapeTopping(Cake cake) {
        super(cake);
    }
 
    @Override
    public String getDescription() {
        return cake.getDescription() + ", Grape";
    }
}

// ConcreteDecorator 2
public class StrawberryTopping extends ToppingDecorator {
    public StrawberryTopping(Cake cake) {
        super(cake);
    }
 
    @Override
    public String getDescription() {
        return cake.getDescription() + ", Strawberry";
    }
}

// Concrete
Decorator 3
public class SugarPowderTopping extends ToppingDecorator {
    public SugarPowderTopping(Cake cake) {
        super(cake);
    }
 
    @Override
    public String getDescription() {
        return cake.getDescription() + ", Sugar Powder";
    }
}

// Client
public class CakeShop {
    public static void main(String[] args) {
        Cake cake = new ChocolateCake();
        cake = new StrawberryTopping(cake);
        cake = new GrapeTopping(cake);
        cake = new SugarPowderTopping(cake);
 
        System.out.println("Cake Description: " + cake.getDescription());
    }
}
 
 
 
 
 
Colored by Color Scripter
cs

 

 위 예시를 코드로 바꿔보았다. 데코레이터 패턴의 구조는 Component를 상속받은 Concrete Component와 Decorator 클래스가 존재한다. 이때, Decorator는 Component를 인스턴스로 가진다. Concrete Decorator 클래스에서는 추가할 기능을 구현하는 역할이다.

 

 이 설명과 맞게 코드에서는 ToppingDecorator가 Cake를 위임받아 인스턴스로 가지고 있고, ToppingDecorator를 상속받은 여러 하위 클래스에서 getDiscription 메소드를 구현하며 데코레이터 패턴을 적용하고 있다.

 

의의

 데코레이터 페턴의 강점은 동적으로 프로그램에 기능을 추가한다는 점에서 있는데, 케이크 꾸미기 예시에서 확인할 수 있듯 ToppingDecorator를 상속받은 클래스를 작성하여 케이크를 꾸미는 여러 방법을 추가할 수 있다. 이렇게 하면 기능 추가를 위해 모든 코드를 수정할 필요 없이 더하고 싶은 기능만 작성하면 되므로 SOLID 원칙 중 OCP를 잘 준수하며 프로그램을 설계할 수 있다.

'CS > 객체지향설계 & 패턴' 카테고리의 다른 글

[객체지향설계 & 패턴] 프록시 패턴  (0) 2025.05.30
[객체지향설계 & 패턴] 전략 패턴  (1) 2025.05.21
[객체지향설계 & 패턴] 상태 패턴  (0) 2025.05.21
[객체지향설계 & 패턴] 템플릿 메소드 패턴  (1) 2025.05.21
[객체지향설계 & 패턴] 메멘토 패턴  (0) 2025.05.10
'CS/객체지향설계 & 패턴' 카테고리의 다른 글
  • [객체지향설계 & 패턴] 프록시 패턴
  • [객체지향설계 & 패턴] 전략 패턴
  • [객체지향설계 & 패턴] 상태 패턴
  • [객체지향설계 & 패턴] 템플릿 메소드 패턴
hyeon0117
hyeon0117
컴공으로 살아남기
  • hyeon0117
    컴공 생활기
    hyeon0117
  • 전체
    오늘
    어제
    • 분류 전체보기 (57)
      • Algorithm (2)
      • PS (19)
        • Solve (19)
      • CS (36)
        • 객체지향설계 & 패턴 (12)
        • COLMAP (2)
        • 머신러닝 (1)
        • 프로그래밍 언어론 (19)
        • 형식언어 (1)
        • 운영체제 (1)
  • 블로그 메뉴

    • 홈
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    프로그래밍 언어론
    BOJ
    백준
    선택 정렬
    PS
    백준 25418
    자료형
    언어 타입
    백준 6825
    형식언어론
    그리디 알고리즘
    java
    자료구조
    객체지향언어
    어휘 분석기
    디자인 패턴
    다이나믹 프로그래밍
    boj 1343
    함수
    블록 구조 언어
    soild 패턴
    의미론
    PLT
    알고리즘
    최단 경로
    구현
    객체지향
    객체지향설계
    형식언어
    디자인패턴
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
hyeon0117
[객체지향설계 & 패턴] 데코레이터 패턴
상단으로

티스토리툴바