티스토리 뷰
상속을 이용해 기능을 확장한 예시를 들어보자.
FileOut은 데이터를 파일에 출력하는 기능을 제공한다. 그리고 BufferedOut과 ZipOut은 각각 버퍼 기능과 압축 기능을 추가 제공한다.
그런데 만약 버퍼 기능과 압축 기능을 함께 제공하고 싶다면 어떻게 해야 할까?
이렇게 하위 클래스를 추가해서 구현할 수 있다. 이 방법은 직관적이지만 추가할 수 있는 기능이 많아질 경우 클래스의 개수가 지나치게 많아질 수 있다는 문제가 있다. 이럴 때 사용할 수 있는 것이 바로 데코레이터 패턴이다.
데코레이터 패턴은 상속이 아닌 '위임' 방식으로 기능을 확장한다. 구조가 조금 복잡해보이니 코드를 통해 이해해 보자.
public abstract class Decorator implements FileOut {
private FileOut delegate; //위임 대상
public Decorator(FileOut delegate){
this.delegate = delegate;
}
protected void doDelegate(byte[] data){
delegate.write(data); //delegate에게 쓰는 것을 위임
}
}
public class EncryptionOut extends Decorator {
public EncryptionOut(FileOut delegate){
super(delegate);
}
public void write(byte[] data){
byte[] encryptedData = encrypt(data);
super.doDelegate(encryptedData);
}
private byte[] encrypt(byte[] data){
...
}
}
Decorator 클래스는 하위 구체 클래스를 위한 추상 클래스이다. FileOut을 delegate로 받아서 쓰기 작업을 delegate에게 위임한다.
EncryptionOut 클래스는 Decorator 클래스를 implement 한다. 데이터를 암호화하고, 쓰기 작업을 delegate에게 실제로 위임하는 기능을 한다.
그렇다면 위 클래스들이 동작하는 예시 코드를 한번 살펴보자.
FileOut delegate = new FileOutImpl();
FileOut fileOut = new EncryptionOut(delegate);
fileOut.write(data);
먼저 실제로 데이터를 쓰는 역할을 하는 delegate은 FileOutImpl 로 생성한다.
그리고 암호화 기능을 추가하기 위해 fileOut은 EncryptionOut 으로 생성한다.
이어서 fileOut으로 write() 메소드를 호출한다.
이해를 돕기 위해 fileOut.write(data)의 실행 과정을 정리해보자.
- EncryptionOut 에 있는 write가 호출된다. 그래서 data가 encrypt 된다.
- super.doDelegate(encrypedData) 코드로 암호화된 data가 Decorator 클래스로 넘어간다.
- Decorator 에 있는 doDelegate() 코드로 delegate.write(data)가 수행된다. 이때 delegate는 fileOutImpl 객체이다.
- fileOutImpl 에 있는 write()가 수행된다.
위 과정에서, EncryptionOut 객체는 데이터를 암호화하는 기능을 장식처럼 얹어 준다. 그래서 EncryptionOut 객체를 데코레이터(Decorator)라고 부른다.
데코레이터 패턴의 장점은, 데코레이터를 조합해서 기능을 추가할 수 있다는 점이다.
FileOut delegate = new FileOutImpl();
FileOut fileOut = new EncryptionOut(new ZipOut(delegate));
fileOut.write(data);
만약 데이터를 압축한 후 암호화하고 싶다면 위와 같이 데코레이터를 추가해주면 된다.
데코레이터 패턴의 또 다른 장점은, 각 추가 기능들이 별도의 클래스로 구현되기 때문에 개별 추가 기능을 변경할 때 다른 추가 기능의 코드는 영향을 받지 않는다는 것이다. 예를 들어 EncrytionOut 클래스에 있는 암호화 알고리즘을 변경하더라도 ZipOut 클래스, FileOutImpl 클래스 등은 수정하지 않아도 된다. 다시 말해 단일 책임 원칙이 지켜지며, 기능의 변경이 쉬워진다.
코드 출처, 참고 도서 : 개발자가 반드시 정복해야 할 객체 지향과 디자인 패턴, 최범균 지음, 인투북스
'OOP' 카테고리의 다른 글
프록시 패턴 vs 데코레이터 패턴 (0) | 2022.09.18 |
---|---|
템플릿 메서드 / 전략 / 템플릿 콜백 패턴 차이 (0) | 2022.09.18 |
예시로 이해하는 상태(State) 패턴 (0) | 2021.06.28 |
예시로 이해하는 템플릿 메소드(Template Method) 패턴 (0) | 2021.06.27 |
예시로 이해하는 전략(Strategy) 패턴 (0) | 2021.06.27 |
- Total
- Today
- Yesterday
- 템플릿콜백
- 김영한
- 스프링
- AOP
- 프로그래머스
- 토비의스프링
- 객체지향
- 서비스추상화
- 프록시패턴
- c++
- 자바스터디
- 코딩테스트
- 토비
- 자바
- OOP
- 코테
- 토비의봄TV
- 데코레이터패턴
- provider
- SOLID
- ec2
- 프록시
- java
- 백기선
- 디자인패턴
- 예외처리
- 카카오
- gracefulshutdown
- BOJ
- 메서드레퍼런스
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |