데코레이터 패턴
Coddy Java 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 87개 중 72번째.
Decorator 패턴은 객체를 decorator라고 하는 특수한 객체로 감싸 객체에 새로운 동작을 추가할 수 있게 해 주는 구조적 디자인 패턴입니다. 컴파일 시점에 동작을 추가하는 상속과 달리, decorator는 원래 class를 수정하지 않고 런타임에 동적으로 기능을 추가합니다.
기본 coffee로 시작하고 우유, 설탕 또는 휘핑크림과 같은 추가 항목을 넣을 수 있는 커피숍을 상상해 보세요. 각 추가 항목은 원래의 coffee를 감싸면서 비용과 설명을 더합니다. 이 패턴은 공통 인터페이스를 사용하므로 decorated 객체를 원래 객체와 동일하게 다룰 수 있습니다:
interface Coffee {
String getDescription();
double getCost();
}
class SimpleCoffee implements Coffee {
public String getDescription() {
return "Simple Coffee";
}
public double getCost() {
return 2.0;
}
}
abstract class CoffeeDecorator implements Coffee {
protected Coffee coffee;
public CoffeeDecorator(Coffee coffee) {
this.coffee = coffee;
}
}
class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee coffee) {
super(coffee);
}
public String getDescription() {
return coffee.getDescription() + ", Milk";
}
public double getCost() {
return coffee.getCost() + 0.5;
}
}decorator는 래핑된 객체에 대한 참조를 보유하고, 자체 동작을 추가하면서 해당 객체에 호출을 위임합니다. 여러 decorator를 쌓아 기능을 결합할 수 있습니다:
Coffee order = new SimpleCoffee();
order = new MilkDecorator(order);
order = new SugarDecorator(order);
System.out.println(order.getDescription()); // 기본 커피, 우유, 설탕
System.out.println(order.getCost()); // 2.75Decorator 패턴은 서브클래스를 폭발적으로 늘리지 않고 객체에 책임을 추가해야 할 때 빛을 발합니다. 각 decorator는 독립적이므로 자유롭게 조합하여 필요한 동작을 정확히 구성할 수 있습니다.
챌린지
쉬움Decorator Pattern을 사용하여 알림 시스템을 만들어 봅시다! 서로 다른 전송 채널, 이메일 알림, SMS 알림, 푸시 알림으로 확장할 수 있는 기본 알림을 만들고, 데코레이터를 서로 감싸 구성합니다. 이는 하나의 메시지를 여러 채널을 통해 동시에 전송해야 할 수 있는 실제 시스템을 반영합니다.
코드를 네 개의 파일로 구성합니다.
Notifier.java: Decorator Pattern의 component interface 역할을 하는Notifierinterface를 Define합니다. 알림 전송을 처리하는send(String message)메서드를 Declare해야 합니다.BasicNotifier.java:Notifier를 implements하는 concrete component class를 Create합니다. 이는 가장 간단한 형태의 알림인 인앱 알림을 나타냅니다.send가 호출되면In-App: [message]를 출력해야 합니다.NotifierDecorators.java: 여기에서 decorator hierarchy를 만듭니다. 먼저Notifier를 implements하고, 래핑된Notifier객체에 대한 reference를 보유하는 abstractNotifierDecoratorclass로 시작합니다(이 객체는 constructor를 통해 전달됩니다).그런 다음
NotifierDecorator를 확장하는 세 개의 concrete decorator를 만듭니다.EmailDecorator-send가 호출되면 먼저 래핑된 notifier에 위임한 다음Email: [message]를 출력합니다.SMSDecorator-send가 호출되면 먼저 래핑된 notifier에 위임한 다음SMS: [message]를 출력합니다.PushDecorator-send가 호출되면 먼저 래핑된 notifier에 위임한 다음Push: [message]를 출력합니다.Main.java: decorator system을 하나로 결합합니다! 두 가지 입력을 받습니다. 알림 메시지(String)와 추가할 채널의 comma-separated 목록(String>)입니다. 예를 들면 <code>"email,sms"또는"push,email,sms"입니다.BasicNotifier로 시작합니다. 그런 다음 channels input에 따라 표시된 순서대로 적절한 decorator로 감쌉니다. 유효한 channel 이름은email,sms,push입니다.마지막으로 fully decorated notifier에서 메시지를 사용하여
send를 호출합니다.
두 가지 입력을 순서대로 받습니다. 전송할 메시지(String)와 활성화할 channels(String, comma-separated)입니다.
예를 들어 입력이 Server is down! 및 email,push인 경우 출력은 다음과 같습니다.
In-App: Server is down!
Email: Server is down!
Push: Server is down!각 decorator가 원래 알림을 유지하면서 자체 동작을 추가하는 방식을 확인하세요. wrapping 순서가 출력 순서를 결정합니다. 가장 안쪽 component(BasicNotifier)가 먼저 실행되고, 그다음 각 decorator가 자신의 layer를 추가합니다. 각 조합에 대해 별도의 class를 만들지 않고도 원하는 channels 조합을 자유롭게 구성할 수 있습니다!
직접 해보기
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 전송할 메시지 읽기
String message = scanner.nextLine();
// 쉼표로 구분된 채널 목록 읽기 (예: "email,sms" 또는 "push,email,sms")
String channelsInput = scanner.nextLine();
// TODO: BasicNotifier로 시작하기
// TODO: 쉼표를 기준으로 채널 입력 분할하기
// TODO: 각 채널을 순회하며 적절한 데코레이터로 notifier 감싸기
// 유효한 채널: "email", "sms", "push"
// TODO: 메시지와 함께 완전히 데코레이트된 notifier에서 send 호출하기
}
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
4상속
상속의 기초 (extends)super 키워드메서드 오버라이딩 (@Override)생성자 체이닝Object 클래스단일 및 다중 레벨 상속다중 클래스 상속이 불가능한 이유요약 - 직원 계층 구조직접 연습해 보세요: 온라인 Java 컴파일러