데코레이터 패턴이란?
객체에 책임을 동적으로 추가하는 패턴을 말합니다.
데코레이터 패턴을 주로 사용하는 상황
- 클래스의 요소들을 조금씩 수정해가면서 사용하는 경우
- 여러 요소들을 조합하여 구성하는 경우
예시
데코레이터 패턴을 설명하는 대표적인 예시로 커피가 있습니다.
아메리카노 = 에스프레소 + 물
카페라떼 = 에스프레소 + 우유 + 휘핑크림
이런식으로 다양한 재료들을 합쳐서 커피를 만들어야한다고 합시다.
만약, 재료들을 전부 다 클래스로 구현해준다면 굉장히 비효율적일 것입니다. 새롭게 커피를 개발하여 새로운 재료가 필요하다면, 그럴 때마다 새롭게 재료의 클래스를 만들어줘야하기 때문입니다. 이를 해결하기 위해 데코레이터 패턴을 적용해봅시다.
public interface Ingredient { String add(); //재료 추가 }
재료라는 인터페이스를 만들고, 재료를 추가하는 행위를 정의합니다.
public class Espresso implements Ingredient { @Override public String add() { return "에스프레소"; } }
커피의 근간이 되는 에스프레소입니다.
public abstract class Decorator implements Ingredient { private Ingredient coffeeIngredient ; public Decorator(Ingredient coffeeIngredient) { this.coffeeIngredient = coffeeIngredient ; } public String add() { return coffeeIngredient.add(); } }
Decorator는 커피 재료들의 근간이 되는 추상클래스입니다. 추가되는 재료들은 클래스를 상속 받아 재료를 추가합니다.
public class WaterDecorator extends Decorator { public WaterDecorator(Ingredient coffeeIngredient) { super(coffeeIngredient); } @Override public String add() { return super.add() + " + 물"; } }
public class MilkDecorator extends Decorator { public MilkDecorator(Ingredient coffeeIngredient) { super(coffeeIngredient); } @Override public String add() { return super.add() + " + 우유"; } }
public class Main { public static void main(String[] args) { Ingredient espresso = new Espresso(); System.out.println("에스프레소 : " + espresso.add()); Ingredient americano = new WaterDecorator(new Espresso()); System.out.println("아메리카노 : " + americano.add()); Ingredient latte = new MilkDecorator(new WaterDecorator(new Espresso())); System.out.println("라떼 : " + latte.add()); } }
이처럼 동적으로 원하는 것을 추가해줄 수 있는 장점이 있습니다.