[디자인 패턴] 7. Decorator 패턴

김주희's avatar
Jul 24, 2025
[디자인 패턴] 7. Decorator 패턴
notion image
 
 
책임 분리하고 ~하고 나서 패턴 적용 (SOLID가 적용되고 난 뒤에 패턴을 적용한다 = 전략 패턴을 지키고 나서 패턴 적용한다)
 
데코레이터 패턴의 목적은 기능의 확장이다.
그럼 상속 아닌가? 라는 생각이 들 수 있다.
 
 

예제 - 알림 보내기

1단계

DIP고 OCP고 뭐고 생각하고 설계하고 만들지 말자. 처음에는 일단 만들어야 한다.
notion image
notion image
 
이메일 알림 클래스는 팀원이 만들었다고 가정하자. 즉 나는 아래의 코드를 모르고 있는 상황이다.
notion image
 
이메일 알림을 쓰려고 하니까 send가 없네? 지금은 툴이 있으니까 알 수 있지만 이전에는 모르거나 send라는 일관성이 없다.
 
강제성을 주기 위해 추상 메서드를 사용한다. 이때 인터페이스든 추상 클래스든 상관 없다. 따라서 추상 메서드를 쓰게 되면 강제성이 부여되는 것 뿐만 아니라 추상화까지 적용된다.
notion image
 
notion image
notion image
notion image
 
 
notion image
notion image
 
 

2단계 : email 알림과 기본 알림을 같이 보내고 싶어!

notion image
notion image
notion image
 
 
⇒ 2번 호출이 아니라 한 번의 호출로 이메일과 기본 알림 둘 다 보낼 수 있도록 해주는게 데코레이터 패턴!
 

3단계 : 데코레이터 패턴을 적용해보자

notifier가 notifier를 has해서 재귀적으로 해결 가능하다.

1. 이메일 알림

notion image
 
notion image
notion image
 
null 넣는거 불편ㅠ → 기본 생성자를 만들자
notion image
notion image
 

2. 기본 + 이메일, 문자 + 이메일

notion image
 

3. 문자 알림 + 이메일 알림 + 기본 알림

기본 알림에는 없는게 좋음 끝이 잇어야 하니께..
notion image
 

4. 문자 알림 + 문자 알림 + 이메일 알림 + 기본 알림

notion image
 

5. 이제 저 선택 값들을 가지고 어떻게 객체를 만들지?

  1. for문 돌리기
  1. reflection
{ "userId" : 5, "notiTypeList" : ["sms", "sms", "email", "basic"] }
notion image
notion image
 
 

그래서 reflection을 적용한다면?

package ex06; import ex06.notification.Notifier; import java.util.List; public class App { public static void main(String[] args) throws Exception { List<String> notiTypeList = List.of("sms", "sms", "email", "basic"); Notifier chain = NotifierFactory.buildNotifierChain(notiTypeList); ClientNotification.send(chain); } }
 
package ex06; import ex06.notification.Notifier; import java.util.List; public class NotifierFactory { public static Notifier buildNotifierChain(List<String> typeList) throws Exception { Notifier chain = null; for (int i = typeList.size() - 1; i >= 0; i--) { String type = typeList.get(i); String className = "ex06.notification." + capitalize(type) + "Notifier"; Class<?> clazz = Class.forName(className); if (chain == null) { chain = (Notifier) clazz.getDeclaredConstructor().newInstance(); } else { chain = (Notifier) clazz.getDeclaredConstructor(Notifier.class).newInstance(chain); } } return chain; } private static String capitalize(String str) { return str.substring(0, 1).toUpperCase() + str.substring(1); } }
 
구조
App → 프로그램 실행 시작 └─> NotifierFactory → 알림 체인을 생성 └─> ClientNotification.send() → 알림 전송
 
Reflection 구현
Share article

jay0628