티스토리 뷰

728x90
반응형

데코레이터 패턴

객체에 추가적인 요건을 동적으로 첨가한다. (구성과 위임을 통해)
데코레이터는 서브클래스를 만드는 것을 통해서 기능을 유연하게 확장할 수 있는 방법을 제공한다.
  • 데코레이터 패턴에서는 구상 구성요소를 감싸주는 데코레이터들을 사용한다.
  • 데코레이터 클래스의 형식은 그 클래스가 감싸고 있는 클래스의 형식을 반영한다.
    (상속, 인터페이스 구현을 통해 자신이 감쌀 클래스와 같은 형식을 가지게 된다.)
  • 데코레이터에서는 자기가 감싸고 있는 구성요소의 메소드를 호출한 결과에 새로운 기능을 더함으로써 행동을 확장한다.
  • 구성요소의 클라이언트 입장에서는 데코레이터의 존재를 알 수 없다.
  • 데코레이터 패턴을 사용하면 자잘한 객체들이 매우 많이 추가될 수 있고, 코드가 복잡해질 수 있다.

 

public abstract class Beverage {	//추상 구성요소
	String description ="제목없음";
	
	public String getDescription() {
		return description;
	}
	
	public abstract double cost();	//서브클래스에서 구현
}

public class HouseBlend extends Beverage {	//래핑되는 구상 컴포넌트
	public HouseBlend() {
		description = "HouseBlend";
	}
	
	public double cost() {
		return .89;
	}
}

public abstract class CondimentDecorator extends Beverage {	//추상 데코레이터

	protected Beverage beverage;

	public CondimentDecorator(Beverage beverage) {
		this.beverage = beverage;
	}
	public abstract String getDescription();	//모든 첨가물 데코레이터에서 구현

	public abstract double cost();
}

public class Soy extends CondimentDecorator {	//구상 데코레이터

	public Soy(Beverage beverage) {
		super(beverage);        //모카가 들어간 음료
	}
	
	public String getDescription() {
		return beverage.getDescription() + ", Soy";
	}
	
	public double cost() {
		return .15 + beverage.cost();	//모카가 들어간 음료 가격 합산
	}
}

public class Mocha extends CondimentDecorator{		//구상 데코레이터

	public Mocha(Beverage beverage) {
		super(beverage);
	}
	
	public String getDescription() {
		return beverage.getDescription() + ", Mocha";
	}
	
	public double cost() {
		return .20 + beverage.cost();	//음료 가격 합산
	}
}

클라이언트에서 컴포넌트 인터페이스를 통해 여러 데코레이터들로 래핑할 수 있다.

public static void main(String[] args) {
    Beverage beverage3 = new HouseBlend();	//음료
    beverage3 = new Mocha(beverage3);		//모카가 들어간 음료
    beverage3 = new Mocha(beverage3);
    beverage3 = new Soy(beverage3);			//모카가 들어간 음료에 두유 첨가
    System.out.println(beverage3.getDescription() + " $" + beverage3.cost());	//합쳐진 설명과 합산된 금액
}

데코레이터가 적용된 예 : Java I/O

InputStream : 추상 구성요소
FileInputStream : 데코레이터로 포장될 구상 구성요소
FilterInputStream : 추상 데코레이터
BufferedInputStream : 구상 데코레이터. 입력된 내용을 버퍼에 저장. readLine() 구현
LineNumberInputStream : 구상 데코레이터. 데이터를 읽을 때 행번호를 붙여주는 기능을 추가

디자인 원칙

1. 애플리케이션에서 달라지는 부분을 찾아내고, 달라지지 않는 부분으로부터 분리시킨다. (캡슐화)
2. 구현이 아닌 인터페이스에 맞춰서 프로그래밍한다.
3. 상속보다는 구성을 활용한다.
4. 서로 상호작용을 하는 객체 사이에서는 가능하면 느슨하게 결합하는 디자인을 사용해야 한다.
5. 클래스는 확장에 대해서는 열려 있어야하지만 코드 변경에 대해서는 닫혀 있어야 한다.
728x90
반응형
반응형
300x250