FireDrago
[객체지향과 디자인패턴] 데코레이터 패턴 본문
데코레이터 패턴
상속을 이용한 기능 확장 방법은 쉽지만, 다양한 조합의 기능의 조합이 요구될때,
불필요한 클래스가 너무 많이 증가하는 문제가 있다.

데코레이터 패턴은 상속이 아니라 위임의 방식으로 기능을 확장하는 디자인 패턴이다.
데코레이터 패턴은 별도의 Decorator 추상 클래스를 사용한다.
public abstract 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) {
bvyte[] encryptionData = encrypt(data);
super.doDelegate(encryptedData); // 상위 클래스에 doDelegate 위임
}
// 암호화 로직
private byte[] encrypt(byte[] data) {
...
}
}
위 코드는 Decorator 클래스를 상속받는다. 이 클래스는 자신의 기능(암호화)을 수행한 뒤에
상위 클래스의 doDelegate() 메서드를 이용해서 파일 쓰기를 위임하도록 구현한다.
FileOut delegate = new FileOutImpl();
FileOut fileOut = new EncryptionOut(delegate);
fileOut.write(data);
위 코드를 사용할때는 이렇게 사용할수 있다.
데코레이터 패턴은 기능을 조합하는 방식으로 확장 할 수 있다.
기능 적용의 순서도 자유롭게 변경할 수 있다.
// 버퍼 -> 암호화 -> 압축 -> 파일 쓰기
FileOut fileOut = new BufferedOut(EncrptionOut(new ZipOut(delegate)));
// 암호화 -> 압축 -> 버퍼 -> 파일 쓰기
FileOut fileOut = new EncryptionOu(new ZipOut(new BufferedOut(delegate)));
데코레이터 패턴을 적용할 때 고려할 점
1. 데코레이터 패턴을 구현할때 정의되어 있는 메서드가 증가하게 되면 그 만큼 데코레이터의 구현도 복잡해진다.
2. 여러개의 데코레이터 객체가 사용될때 그 중 하나가 비정상적으로 작동하면 어떻게 처리할 지 고려해야한다.
필수적인 기능의 문제라면 예외를 발생시킨다. 반면 부가적인 기능이라면 로그를 남기고 사후처리를 할 수도 있다.
3. 클라이언트 입장에서 데코레이터 객체와 실제 구현 객체의 구분이 힘들기 때문에 코드로 기능을 이해하기 어렵다.
public class ImageSource {
public void writeTo(FileOut out) {
out.write(imagedata);
}
...
}
위 코드에서 writeTo() 메서드는 파라미터로 전달받은 FileOut 객체를 사용하는데
writeTo() 메서드는 이 FileOut 객체가 단순히 파일에 쓰기만 하는지 아니면 압축을 하는지 등의 여부를 알 수 없다.
