디자인 원칙
개방 폐쇄 원칙(OCP - Open Closed Principle)
- 클래스는 확장에는 열려 있어야 하지만 변경에는 닫혀 있어야 한다
데코레이터 패턴(Decorator Pattern)
- 객체에 추가 요소를 동적으로 추가 가능(상속이 아닌 객체를 감싸는 방식으로 기능 추가 & 변경)
- 이 패턴을 사용하면 서브 클래스를 만들 때보다 훨씬 유연하게 기능을 확장할 수 있다
패턴 구조

- Component : 기본 기능을 정의하는 인터페이스로 데코레이터와 구체적인 컴포넌트가 이를 구현한다. 따라서 컴포넌트는 원본 객체와 데코레이터를 묶는 역할을 한다.
- ConcreteComponent : 기본 기능을 실제로 구현하는 구체적인 컴포넌트로 데코레이터 패턴의 시작점이 된다.
- Decorator : 컴포넌트를 감싸는 추상 클래스나 인터페이스로 새로운 기능을 추가하거나 기존 기능을 수정하기 위한 메서드를 선언한다. 데코레이터는 Component를 멤버 변수로 가진다.
- ConcreteDecorator : 새로운 기능이나 기존 기능을 수정하는 역할을 하는 구체적인 클래스다. 데코레이터 인터페이스를 구현한다.
특징
- 데코레이터의 슈퍼 클래스는 자신이 장식하고 있는 객체의 슈퍼 클래스와 같다
- 한 객체를 여러 개의 데코레이터로 감쌀 수 있다
- 데코레이터는 자신이 감싸고 있는 객체와 같은 슈퍼클래스를 가지고 있기에 원래 객체(싸여 있는 객체)가 들어갈 자리에 데코레이터 객체를 넘어도 상관 없다
- 데코레이터는 자신이 장식하고 있는 객체에게 어떤 행동을 위임하는 일 말고도 추가 작업을 수행할 수 있다
- 객체는 언제든지 감쌀 수 있기 때문에 실행 중에 필요한 데코레이터 마음대로 적용 가능
단점
- 잡다한 클래스가 많아진다
- 구성요소를 초기화하는 데 필요한 코드가 훨씬 복잡해진다
- 특정 형식에 의존하는 코드에 데코레이터를 그냥 적용할 수 없다
예제
public abstract class Beberage {
String description = "제목 없음";
public String getDescription() {
return description;
}
public abstract double cost();
}
public abstract class CondimentDecorator extends Beverage {
Beverage beverage;
public abstract String getDescription();
}
public class Espresso extends Beverage {
public Espresso() {
description = "에소프레소";
}
public double cost() {
return 1.99;
}
}
public class HouseBlend extends Beverage {
public HouseBlend() {
description = "하우스 블렌드 커피";
}
public double cost() {
return .89;
}
}
public class Mocha extends CondimentDecorator {
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", 모카";
}
pulibc double cost() {
return beverage.cost() + .20;
}
}
public class Soy extends CondimentDecorator {
public Soy(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", 두유";
}
pulibc double cost() {
return beverage.cost() + .15;
}
}
public class Whip extends CondimentDecorator {
public Whip(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", 휘핑크림";
}
pulibc double cost() {
return beverage.cost() + .10;
}
}
public class StarbuzzCoffee {
public static void main(String args[]) {
Beverage beverage = new Espresso();
System.out.println(beverage.getDescription() + " $" + beverage.cost());
Beverage beverage2 = new DarkRost();
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());
}
}
// 결과
에소프레소 $1.99
다크 로스트 커피, 모카, 모카, 휘핑크림 $1.49
하우스 블렌드 커피, 두유, 모카, 휘핑크림 $1.34
적용 예시
- 자바 I/O

Create sub-issue
👍1
'후기' 카테고리의 다른 글
| 데보션 스프링 스터디 후기 (2) | 2025.08.08 |
|---|---|
| 자바 ORM 표준 JPA 프로그래밍 - 영속성 관리 (0) | 2025.04.02 |
| 자바 ORM 표준 JPA 프로그래밍 - jpa 소개 (0) | 2025.04.02 |
| 옵저버 패턴 (0) | 2025.03.30 |
| 디자인 패턴 소개와 전략 패턴 (0) | 2025.03.30 |