[디자인패턴] 7. Decorator Pattern

문정준's avatar
Jul 23, 2025
[디자인패턴] 7. Decorator Pattern

Decorator Pattern

  • 주어진 상황 및 용도에 따라 어떤 객체에 책임을 덧붙이는 패턴
 

책임을 추가하는 방법

  1. 상속 (extends) : 하나의 클래스밖에 상속받을 수 없음
  1. 컴퍼지션 : 코드 수정 시 전체 코드를 다 수정해야 함 (OCP 위배)
  1. 추상 메서드 + 추상 클래스 or 인터페이스 : 추상화를 통한 DIP + OCP + 코드 구현의 강제성 부여 가능
      • 인터페이스 + 컴퍼지션 조합이 제일 이상적인 데코레이터 패턴
 

Ex. 알림 보내기

  • 사용자에게 어떤 메시지를 보내려고 할 때, 기본 / 이메일 / 문자의 방법을 사용해서 보내고 싶음
  • 1개씩 선택하거나, 2개씩 선택하거나, 전부 다 선택하는 방법도 존재
 

Q1. 조건문으로 만든다면?

  • 위 예제에서는 선택지가 3개밖에 없다 해도 총 경우의 수는 7개가 존재
  • 실제로 선택지가 늘어나게 되면 해당 경우의 수에 따라 케이스를 모두 만들어야 함
    • 케이스 예상을 할 수 없고 책임이 증가하게 됨 (SRP 위반)
 

Q2. 데코레이터 패턴을 사용하면?

  • 각 알림을 보내기 위한 Notifier를 구현 (Basic, Email, SMS)
  • 추상화를 위한 Notifier 인터페이스 구현 및 각 Notifier들에게 연결
    • Notifier에서 작성하였던 추상 메서드를 구현해야 하므로 코드의 컨벤션 또한 지켜짐
  • 내부 함수에서 Notifier의 알림 전송 메서드 호출
  • 실행 시 필요한 Notifier들을 연쇄 호출 (Notifier의 함수에 직접 접근하지 않고 Adapter 등 사용)
    • 필요한 Notifier들을 Static Factory 등을 사용하여 호출할 수 있음
notion image

코드

  • App.java
public class App { public static void main(String[] args) { // Notifier b1 = new BasicNotifier(); // b1.send(); // System.out.println("_end"); // // Notifier e1 = new EmailNotifier(); // e1.send(); // System.out.println("_end"); // // Notifier s1 = new SMSNotifier(); // s1.send(); // System.out.println("_end"); // 1. 이메일 알림 // 하나의 호출 만으로 기본 알림 및 이메일 알림을 동시에 보내는 것이 목표 EmailNotifier e1 = new EmailNotifier(); e1.send(); System.out.println("_end"); // 2. 이메일 + 기본 알림 EmailNotifier e2 = new EmailNotifier(new BasicNotifier()); e2.send(); System.out.println("_end"); // 3. 이메일 + 문자 알림 EmailNotifier e3 = new EmailNotifier(new SMSNotifier()); e3.send(); System.out.println("_end"); // 4. 문자 + 기본 알림 SMSNotifier s1 = new SMSNotifier(new BasicNotifier()); s1.send(); System.out.println("_end"); // 5. 문자 + 이메일 + 기본 알림 Notifier n1 = new SMSNotifier(new EmailNotifier(new BasicNotifier())); n1.send(); System.out.println("_end"); // 6. 문자 2번 -> 이메일 1번 -> 기본 알림 Notifier n2 = new SMSNotifier(new SMSNotifier(new EmailNotifier(new BasicNotifier()))); ClientNotification.noti(n2); } }
 
  • ClientNotification.java
public class ClientNotification { public static void noti(Notifier notifier) { notifier.send(); } }
 
  • Notifier.java
// 팀원이 만든 코드와 내가 만든 코드의 일관성이 깨짐 // 강제성 부여 필요 : 추상 메서드 (인터페이스 or 추상 클래스) -> 자동 추상화 public interface Notifier { void send(); }
 
  • BasicNotifier.java
public class BasicNotifier implements Notifier { public void send() { System.out.println("기본 알림"); } }
 
  • EmailNotifier.java
    • Notifier를 컴퍼지션으로 사용 : Notifier 연쇄 호출 가능
    • 기본 생성자 : notifier가 null일 경우 연쇄 호출 중단
public class EmailNotifier implements Notifier { private Notifier notifier; public EmailNotifier() { } public EmailNotifier(Notifier notifier) { this.notifier = notifier; } @Override public void send() { System.out.println("이메일 알림"); if(notifier != null) {notifier.send();} } }
 
  • SMSNotifier.java
public class SMSNotifier implements Notifier { public SMSNotifier() { } private Notifier notifier; public SMSNotifier(Notifier notifier) { this.notifier = notifier; } @Override public void send() { System.out.println("문자 알림"); if(notifier != null) {notifier.send();} } }
 
Share article

sxias