목차
개요
이번 글에선 Object Structural Pattern인 데코레이터 패턴에 대해 알아보겠습니다
내용
요약
객체에 역할을 동적으로 부여하자. 기능을 확장함으로써 상속을 대체할 수 있다.
예시
이번에도 디자인 패턴 예시의 국룰인 GUI 프레임워크를 생각해봅시다. 사용자가 어떤 도형을 생성했을 때, 그 도형엔 외곽선이나 스크롤 등을 추가해줄 수 있으면 좋을 것입니다. 이런 요구사항을 해결하기위한 방법 중 하나는 상속인데요. 상속은 유연하지 않습니다. 도형이라는 객체가 생성된 이후에 해당 객체에 상속을 동적으로 추가할 순 없기 때문입니다.
이럴 때 사용할 수 있는 더 유연한 방법은 도형 객체 바깥으로 외곽선을 추가해주는 다른 객체를 두르는 것입니다. 둘러싸는 객체를 데코레이터라고 합니다. 일반적으로 데코레이터는 감싸는 클래스의 인터페이스에 맞춰 작성함으로써 사용자가 알지 못하게 합니다. 데코레이터는 감싸는 컴포넌트로 요청이 오기 전/후에 특정 액션을 취합니다.

구조

이야깃거리
언제 써야 할까?
- 다른 객체에 영향을 주지 않으면서 객체에 동적으로 역할을 추가하고 싶을 때
- 객체에 없앨 수 있는 역할을 추가하고 싶을 때
- 상속을 통한 확장이 쉽지 않을 때. 예를 들어, 위 예시에서 스크롤, 외곽선만 있다면 스크롤만 상속받는 Component, 외곽선만 상속받는 Component, 외곽선, 스크롤을 모두 상속받는 Component, 모두 상속받지 않는 Component를 모두 정의해야 합니다. 이는 각 요소의 수에 대한 조합과 같은 수의 subclass를 만들어야 한다는 뜻이 됩니다. <<GoF Design Pattern>>에선 이와 같은 현상을 explosion of subclass라고 말합니다. 이런 경우가 발생할 때, 데코레이터 패턴을 쓰는 것이 좋을 수 있습니다.
장단점
- (Pros) 클래스의 수를 늘리지 않으면서 객체에 역할을 추가할 수 있습니다.
- (Cons) 작은 객체의 수가 많이 늘어날 수 있습니다.
Case Study
Case 1. Java IO
자바의 BufferedInputStream, FileInputStream 등은 모두 InputStream을 받는 생성자를 가지고 있습니다. 즉, 바이트를 읽기 전/후의 작업에 데코레이팅을 할 수 있는 클래스란 뜻입니다. 아래와 같은 예시를 생각해봅시다.
먼저 파일을 엽니다.
FileInputStream fis = new FileInputStream("/objects.gz");
그 다음, 성능을 위해 버퍼를 둡니다.
BufferedInputStream bis = new BufferedInputStream(fis);
압축이 되어있다면 압축을 풉니다.
GzipInputStream gis = new GzipInputStream(bis);
마지막으로 바이트를 자바 객체로 변환합니다.
ObjectInputStream ois = new ObjectInputStream(gis);
이제 InputStream을 사용해보죠.
SomeObject someObject = (SomeObject) ois.readObject();
FileInputStream을 다른 InputStream들이 데코레이팅했다고 생각할 수 있을 것입니다.
출처
GoF Design Patterns
https://stackoverflow.com/a/6366543
'Design Patterns' 카테고리의 다른 글
[Design Patterns] Flyweight (1) | 2024.03.27 |
---|---|
[Design Patterns] Facade (0) | 2024.03.24 |
[Design Patterns] Composite (0) | 2024.03.17 |
[Design Patterns] Bridge (0) | 2024.03.16 |
[Design Patterns] Adapter (0) | 2024.03.16 |