| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | ||
| 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 13 | 14 | 15 | 16 | 17 | 18 | 19 |
| 20 | 21 | 22 | 23 | 24 | 25 | 26 |
| 27 | 28 | 29 | 30 |
- PHP
- MySQL
- 매직메서드
- Agent Loop
- 객체지향
- LLM
- 인덱스
- mcp client
- 객체복제
- ai agent
- ai 에이전트
- PHP객체지향
- SQL문법
- 소프트웨어설계
- SQL기초
- Laravel
- SQL
- 데코레이터패턴
- linux 권한
- 라라벨
- 데이터베이스
- OOP
- 디자인패턴
- mcp server
- 어댑터패턴
- docker network
- docker
- MCP
- dhgrp
- Tool Calling
- Today
- Total
개발블로그
[디자인패턴] 데코레이터 패턴 본문
개념
필요성
프로그램을 만들다 보면 기존 기능은 유지하면서, 그 앞뒤로 부가 기능을 추가해야 하는 경우가 있다.
EX]
결제 기능
payment.pay(10000)
처음에는 결제만 처리하면 충분할 수 있다.
하지만 시간이 지나면 결제 전후로 여러 기능이 추가될 수 있다.
ex) 로깅, 권한 확인, 캐싱, 알림
기능들이 기존 결제 클래스 안에 계속 추가되면, 클래스의 책임이 점점 커짐.
class PaymentService:
def pay(self, amount):
check_permission()
write_log("결제 시작")
result = process_payment(amount)
send_notification()
write_log("결제 완료")
return result
문제는 결제 기능 자체와 부가 기능이 강하게 묶인다.
나중에 로깅만 제거하거나, 알림만 다른 상황에서 추가하고 싶을 때 유연하게 조합하기 어려움.
" 기존 객체를 직접 수정하지 않고, 기능을 덧붙일 수 없을까?"
의미
기존 객체를 감싸는 방식으로 부가 기능을 추가하는 패턴
기존 객체의 코드는 그대로 두고, 그 객체를 감싸는 데코레이터 객체가 앞뒤로 추가 동작을 수행
| 구분 | 역할 | 예시 |
| Component | 공통으로 사용할 기능의 형태 | Payment |
| Concrete Component | 기본 기능을 수행하는 실제 객체 | BasicPayment |
| Decorator | 기존 객체를 감싸고 부가 기능을 추가하는 객체 | LoggingPayment, PermissionPayment, NotificationPayment |
핵심은 기존 객체와 데코레이터가 같은 형태의 메서드를 제공함
그래서 사용하는 쪽에서는 기본 객체인지, 데코레이터로 감싼 객체인지 같은 방식으로 사용할 수 있다.
기존 객체를 내부에 가지고 있다가, 필요할 때 기존 객체의 기능을 호출함.
그리고 호출 전후에 자신의 부가 기능을 추가함.
예시
EX]
결제 기능을 담당하는 BasicPayment
class BasicPayment:
def pay(self, amount):
return f"{amount}원 결제 완료"
여러 기능이 추가될 때, 가장 간단한 방법은 기존 클래스 안에 부가 기능을 직접 넣는 것
class BasicPayment:
def pay(self, amount):
check_permission()
write_log("결제 시작")
result = f"{amount}원 결제 완료"
send_notification()
write_log("결제 완료")
return result
| 문제 | 설명 |
| 책임 혼합 | 결제 처리, 권한 확인, 로깅, 알림이 한곳에 섞인다. |
| 조합 어려움 | 어떤 상황에서는 로깅만, 다른 상황에서는 알림만 적용하기 어렵다. |
| 수정 범위 증가 | 부가 기능이 바뀔 때 결제 클래스도 함께 수정된다. |
| 클래스 증가 가능성 | 상속으로 조합하면 경우의 수만큼 클래스가 늘어날 수 있다. |
기본 기능과 부가 기능을 분리하고, 필요한 기능만 조합할 수 있는 구조가 필요함.
=> 데코레이터로 기능 감싸기
결제 객체가 공통으로 제공할 동작을 정한다
class Payment:
def pay(self, amount):
pass
기본 결제 기능은 BasicPayment가 담당
class BasicPayment(Payment):
def pay(self, amount):
return f"{amount}원 결제 완료"
부가 기능은 데코레이터로 분리
class LoggingPayment(Payment):
def __init__(self, payment):
self.payment = payment
def pay(self, amount):
print("결제 시작 로그")
result = self.payment.pay(amount)
print("결제 완료 로그")
return result
내부에 다른 Payment 객체를 가지고 있음.
그리고 pay()를 호출할 때 기존 객체의 pay()를 실행하면서 앞뒤로 로그를 추가
권한 확인도 별도의 데커레이터로 만들 수 있음
class PermissionPayment(Payment):
def __init__(self, payment):
self.payment = payment
def pay(self, amount):
print("권한 확인")
return self.payment.pay(amount)
필요한 기능을 감싸서 조합할 수 있다.
payment = BasicPayment()
payment = LoggingPayment(payment)
payment = PermissionPayment(payment)
payment.pay(10000)
실행흐름)
PermissionPayment.pay()
→ 권한 확인
→ 내부에 감싼 LoggingPayment.pay() 호출
→ 결제 시작 로그
→ 내부에 감싼 BasicPayment.pay() 호출
→ 실제 결제 실행
→ 결제 완료 로그
데코레이터들의 pay()는 같은 결제를 여러 번 실행하는 것이 아니라, 요청을 안쪽 객체로 전달하면서 앞뒤에 부가 기능을 추가하는 역할을 한다.
장점
장점
| 장점 | 설명 |
| 기존 코드 변경 최소화 | 기본 기능을 담당하는 클래스를 직접 수정하지 않고 기능을 추가할 수 있다. |
| 기능 조합 유연성 | 필요한 부가 기능을 원하는 순서로 조합할 수 있다. |
| 책임 분리 | 기본 기능과 부가 기능을 각각 다른 객체로 나눌 수 있다. |
| 상속보다 유연한 확장 | 기능 조합마다 새로운 자식 클래스를 만들 필요가 줄어든다. |
| 실행 시점 조합 가능 | 어떤 데코레이터를 적용할지 실행 중에 선택할 수 있다. |
효과적인 상황
| 상황 | 이유 |
| 기존 코드를 직접 수정하기 어려운 경우 | 기본 객체를 감싸서 기능을 추가할 수 있다. |
| 부가 기능 조합이 여러 가지인 경우 | 상속보다 유연하게 조합할 수 있다. |
| 기능을 실행 시점에 선택해야 하는 경우 | 필요한 데코레이터를 조건에 따라 적용할 수 있다. |
| 기본 기능과 부가 기능을 분리하고 싶은 경우 | 각 기능의 책임을 나눌 수 있다. |
주의점
단점
| 주의점 | 설명 |
| 흐름 추적 어려움 | 여러 객체가 겹쳐 있으면 실제 실행 순서를 파악하기 어려울 수 있다. |
| 순서 의존성 | 권한 확인, 로깅, 알림처럼 실행 순서가 중요한 기능은 조합 순서를 신경 써야 한다. |
| 디버깅 어려움 | 문제가 발생했을 때 어느 데코레이터에서 발생했는지 추적해야 한다. |
| 과한 구조 가능성 | 단순한 기능 추가에는 데코레이터보다 직접 구현이 더 명확할 수 있다. |
| 책임 혼합 위험 | 데코레이터가 부가 기능을 넘어 핵심 비즈니스 로직까지 담당하면 구조가 흐려진다. |
주의점
| 질문 | 의미 |
| 기존 객체를 직접 수정하지 않아야 하는 이유가 있는가? | 데코레이터를 둘 필요가 있는지 확인한다. |
| 부가 기능을 여러 방식으로 조합해야 하는가? | 조합의 이점이 있는지 판단한다. |
| 실행 순서가 중요한가? | 데코레이터를 감싸는 순서를 명확히 해야 한다. |
| 데코레이터가 너무 많이 겹치지 않는가? | 구조가 과하게 복잡해지는지 확인한다. |
| 부가 기능과 핵심 기능의 책임이 분리되어 있는가? | 데코레이터가 핵심 로직을 침범하지 않게 한다. |
'STUDY > CS' 카테고리의 다른 글
| [디자인패턴] 싱글톤 패턴 (0) | 2026.09.04 |
|---|---|
| [디자인패턴] 어댑터 패턴 (0) | 2026.09.04 |
| [디자인패턴] 옵저버 패턴 (0) | 2026.09.04 |
| [디자인패턴] 팩토리 패턴 (1) | 2026.09.04 |
| [디자인 패턴] 전략패턴 (0) | 2026.09.04 |