본문 바로가기

Design-Pattern

개체를 아름답게 꾸미자! 데코레이터 패턴(decorator pattern)

1. 데코레이터 패턴(decorator pattern) 이란?

데코레이터(decorator)를 번역해 보면 장식이라는 뜻을 가지고 있는데

데코페이터 패턴은 객체에 동적으로 기능을 추가하며 객체를 꾸며(장식) 주는 패턴이라고 할 수 있습니다.

아래 그림을 보면 조금더 편하게 이해가 가능합니다

데코레이터 패턴

위 그림 처럼 라떼 아트를 통해 커피에 우유로 이쁘게 모양을 꾸미는 것처럼 기능을 추가하는 형태의 디자인 패턴입니다.

 

이를 UML 다이어 그램으로 표현해 보면 다음과 같습니다.

데코레이터 UML

 

2. 데코레이터 패턴(decorator pattern)의 특징?

데코레이터 패턴은 OCP를 기본 원칙으로 한 것이 특징인데 여기서 OCP란?

OCP(Open-Closed-Principle) : 클래스는 확장에 대해서는 열려 있어야 하지만 코드 변경에 대해서는 닫혀 있어야 한다

기존의 코드는 건드리지 않은 채로 확장을 통해서 새로운 기능을 추가할 때 적합한 패턴입니다

이런 데코레이터 패턴의 특징을 정리해 보면 다음과 같은데

 

1. 데코레이터의 수퍼클래스는 자신이 장식하고 있는 객체의 수퍼클래스와 같습니다.

2. 한 객체를 여러 개의 데코레이터로 감쌀 수 있습니다.

3. 데코레이터는 자신이 감싸고 있는 객체와 같은 수퍼클래스를 가지고 있기 때문에 원래 객체가 들어갈 자리에 데코레이터 객체를 집어넣어도 상관없습니다.

4. 객체는 언제든지 감쌀 수 있기 때문에 실행 중에 필요한 데코레이터를 마음대로 적용할 수 있습니다.

 

3. 데코레이터 패턴(decorator pattern)의 구현

데코레터 패턴을 간단하게 구현해 보면 다음과 같이 구현이 가능합니다.

 

Beverage

public abstract class Beverage {
	String description = "Unknown Beverage";
	public String getDescription() {
		return description;
	}
	public abstract double cost();
}

CondimentDecorator

public abstract class CondimentDecorator extends Beverage {
	Beverage beverage;
	public abstract String getDescription();
}

DarkRoast

public class DarkRoast extends Beverage {
	public DarkRoast() {
		description = "Dark Roast Coffee";
	}
	public double cost() {
		return .99;
	}
}

Decaf

public class Decaf extends Beverage {
	public Decaf() { description = "Decaf Coffee"; }
	public double cost() { return 1.05; }
}

Espresso

public class Espresso extends Beverage {
	public Espresso() { description = "Espresso"; }
	public double cost() { return 1.99;}
}

HouseBlend

public class HouseBlend extends Beverage {
	public HouseBlend() { description = "House Blend Coffee"; }
	public double cost() { return .89; }
}

Milk

public class Milk extends CondimentDecorator {
	public Milk(Beverage beverage) { this.beverage = beverage; }
	public String getDescription() { return beverage.getDescription() + ", Milk"; }
	public double cost() { return .10 + beverage.cost(); }
}

Mocha

public class Mocha extends CondimentDecorator {
	public Mocha(Beverage beverage) { this.beverage = beverage; }
	public String getDescription() { return beverage.getDescription() + ", Mocha"; }
	public double cost() { return .20 + beverage.cost(); }
}

Soy

public class Soy extends CondimentDecorator {
	public Soy(Beverage beverage) { this.beverage = beverage; }
	public String getDescription() { return beverage.getDescription() + ", Soy"; }
	public double cost() { return .15 + beverage.cost(); }
}

StartbuzzCoffee

public class StarbuzzCoffee {
	public static void main(String args[]) {
		Beverage beverage = new Espresso();
		System.out.println(beverage.getDescription() + " $" + beverage.cost());
		Beverage beverage2 = new DarkRoast();
		beverage2 = new Mocha(beverage2);
		beverage2 = new Mocha(beverage2);
		beverage2 = new Whip(beverage2);
		System.out.println(beverage2.getDescription() + " $" + beverage2.cost());
		Beverage beverage3 = new HouseBlend();
		beverage3 = new Soy(beverage3);
		beverage3 = new Mocha(beverage3);
		beverage3 = new Whip(beverage3);
		System.out.println(beverage3.getDescription() + " $" + beverage3.cost());
	}
}