| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 | 31 |
Tags
- Delete
- 벨만-포드
- 트라이
- Github
- 자바스크립트
- 그래프 탐색
- Express.js
- Binary Lifting
- Behavior Design Pattern
- reference counting
- DP
- 비트필드를 이용한 dp
- PROJECT
- SCC
- Prisma
- Spin Lock
- map
- Lock-free Stack
- 최소 공통 조상
- 게임 서버 아키텍처
- JavaScript
- Strongly Connected Component
- 이분 탐색
- trie
- localstorage
- ccw 알고리즘
- 비트마스킹
- R 그래프
- 2-SAT
- 강한 연결 요소
Archives
- Today
- Total
dh_0e
[Design Pattern] Behavior Design Patterns I (Chain of Responsibility Pattern, Command Pattern) 본문
Software Analysis & Design/Design Patterns
[Design Pattern] Behavior Design Patterns I (Chain of Responsibility Pattern, Command Pattern)
dh_0e 2025. 11. 17. 17:41Behavior Design Patterns(행동 패턴)
- 한 객체가 수행할 수 없는 작업을 여러 개의 객체로 어떻게 분배할지, 그렇게 하면서도 객체 사이의 결합도를 최소화하는 것에 중점을 둔 패턴

책임 연쇄 패턴(Chain of Responsibility Pattern)
- 클라이언트의 요청에 대한 세세한 처리를 한 객체가 전부 하는 것이 아닌,
여러 개의 처리 객체들로 나누고 이들을 사슬(chain)처럼 연결해 연쇄적으로 처리하는 행동 패턴- Handler(핸들러): 처리 객체를 지칭
- 요청을 받으면 각 핸들러는 요청을 처리할 수 있는지 판단하고, 없으면 다음 핸들러로 책임을 전가
- Handler(핸들러): 처리 객체를 지칭

- 필요한 상황
- 온라인 주문 시스템을 개발하려고 하는 예시에서,
- 인증된 사용자들만 주문을 생성할 수 있도록 시스템에 대한 접근을 제한
- 관리 권한이 있는 사용자들에게 모든 주문에 대한 전체 접근 권한을 부여
- 이러한 검사들을 차례대로 수행하도록 구성했다고 가정
- 온라인 주문 시스템을 개발하려고 하는 예시에서,

- 검사 조건을 추가하는 상황
- 요청 내의 데이터를 정제(sanitize)하는 유효성 검사 단계를 추가
- 시스템이 무차별 대입 공격을 방어하기 위해 같은 IP 주소에서 오는 반복적으로 실패한 요청을 걸러내는 검사를 즉시 추가
- 데이터가 포함된 반복 요청에 대해 캐시된 결과를 반환하여 시스템 속도를 개선

- 책임 연쇄 패턴의 아이디어
- 특정 행동들을 핸들러라는 독립 실행형 객체로 변환
- 핸들러를 체인으로 연결해서 체인을 따라 요청을 처리할 수 있도록 함
- 경우에 따라서는 핸들러가 요청을 체인 뒤로 더 이상 전달하지 않고, 추가 처리를 중지하는 결정을 할 수도 있음

책임 연쇄 패턴의 구조

| 구성 요소 | 역할 | 상세 설명 |
| 1. Handler | 공통 인터페이스 | 모든 핸들러가 구현해야 할 공통적인 인터페이스를 선언 |
| 2. Base Handler | 추상 클래스 | 모든 핸들러 클래스에 공통적인 상용구 코드를 포함하며, 다음 핸들러 참조를 위한 next 필드 존재 |
| 3. Concrete Handler | 실제 처리 구현 | 요청을 처리하기 위한 실제 코드를 포함 |
| 4. 클라이언트 (Client) | 체인 구성 및 요청 전송 | 애플리케이션의 논리에 따라 체인을 한 번만 구성하거나 동적으로 구성 |
ex)





CoR Pattern 사용 시기
- 특정 요청을 2개 이상의 여러 객체(Handler)에서 판별하고 처리해야 하는 경우
- 특정 순서로 여러 핸들러를 실행해야 하는 경우
- 프로그램이 다양한 방식과 종류의 요청을 처리할 것으로 예상되나, 요청 유형과 순서를 미리 알 수 없는 경우
- 요청을 처리할 수 있는 객체 집합이 동적(런타임)으로 정의되어야 하는 경우
CoR Pattern 장단점
- 장점
- 클라이언트는 처리 객체(handler)의 체인 집합 내부의 구조를 알 필요가 없음 (Black Box)
- SRP 준수: 각각의 체인(handler)은 자신의 해야하는 일만 하기 때문에 새로운 요청 처리에 유연하게 확장 가능
- OCP 준수: 클라이언트 코드를 변경하지 않고 체인(handler)을 동적으로 변경 가능
- main의 체인 구성 코드만 변경하면 됨
- ? main 코드 수정은 client 코드 수정한 거 아냐? 그럼 OCP 준수가 아니잖아!
- >> OCP 준수 맞음
- main의 체인 구성 코드만 변경하면 됨

- 단점
- 실행 시에 코드의 흐름이 많아져서 과정을 한눈에 살펴보기가 복잡함
- 무한 사이클로 체인이 구성되면 무한 루프에 빠질 수 있음
- 책임 연쇄로 인한 처리 지연 문제가 발생할 수 있음
명령 패턴(Command Pattern)
- 정의: 요청을 객체의 형태로 캡슐화하여 사용자가 보낸 요청을 나중에 이용할 수 있도록 재사용성을 높인 행동 패턴
- 요청을 보내는 쪽(invoker)과 요청을 받는 쪽(reciever)을 커맨드를 이용하여 디커플링(Decoupling)하여 재사용을 높이고자 함
- ex) 리모컨(Invoker)의 버튼을 누르면, 그 버튼은 "TV 켜기 명령"이라는 종이를 TV(Receiver)에게 전달 / 리모컨은 TV를 어떻게 켜는지(내부 회로) 몰라도 되며, TV, 에어컨, 오디오 등 어떤 기기에도 똑같은 press() 버튼을 사용할 수 있음

- 필요한 상황
- 텍스트 편집기 앱을 개발하고 있는 상황에서, 편집기의 다양한 작업을 위한 여러 버튼이 있는 도구 모음(toorbar)을 만들고 있다고 가정
- 도구 모음의 버튼과 다양한 대화 상자들의 일반 버튼들에 사용할 수 있는 Button 클래스를 생성
- 텍스트 편집기 앱을 개발하고 있는 상황에서, 편집기의 다양한 작업을 위한 여러 버튼이 있는 도구 모음(toorbar)을 만들고 있다고 가정

- 버튼의 모양은 비슷해 보이지만 각각 다른 기능을 수행해야 함
- 요청을 처리하기 위한 함수를 자식 클래스로 상속하고 오버라이딩하는 구조로 구성해야 한다면 기능별로 상속을 다 해주어야 함

- 이렇게 되면 Button 클래스를 수정할 때마다 자식 클래스가 영향을 받음
- 로직 수정시 관련 모든 클래스 수정해주어야 함
- 동일한 기능을 하는 로직이 버튼이 아닌 다른 형태로 표현될 때 해당 기능을 copy & paste 해야 함

- 명령 패턴의 아이디어
- 인터페이스 객체들이 요청을 직접 보내는 것이 아닌 Command를 경유해서 보내자


- 수정된 구조
- 더 이상 다양한 클릭 행동들을 구현하기 위한 버튼의 여러 자식 클래스는 필요하지 않음
- 커맨드는 사용자 인터페이스와 비즈니스 로직 레이어 간의 결합도를 줄이는 중간 레이어의 역할을 함

- Invoker: 버튼 같은 애
- Command: 버튼이 실행할 '동작'의 인터페이스
- ConcreteCommand1/2: 실제로 "복사하기, 붙여넣기" 같은 구체 동작
- Receiver: 에디터, 서비스 같은 진짜 비즈니스 로직 객체
- Client: 이 관계들을 처음에 연결해주는 설정 코드


- 장점
- 단일 책임 원칙(SRP) 및 개방/폐쇄 원칙(OCP) 준수
- SRP: Invoker와 receiver로 책임을 분리하고, 기존 클라이언트 코드에 변경 없이 새로운 커맨드 도입 가능
- OCP: 새로운 기능을 추가할 때, receiver는 수정이 필요하지 않으며, command만 수정하면 됨
- 클라이언트와 수신자 간의 결합도 감소
- 클라이언트는 어떤 커맨드가 어떤 객체에서 어떻게 실행되는지 세부사항을 알 필요 없음
- 명령 기록과 실행 취소/재실행(undo/redo) 기능 추가 가능
- Invoker 내부에 stack을 이용하여 command history를 관리 가능
- 단일 책임 원칙(SRP) 및 개방/폐쇄 원칙(OCP) 준수
- 단점
- Invoker(Button)와 receiver(Light or Game) 사이에 완전히 새로운 레이어(command)를 도입하기 때문에 코드가 더 복잡해짐
Summary

- 책임 연쇄 패턴(Chain of Responsibility Pattern)
- 클라이언트의 요청에 대한 세세한 처리를 한 객체가 전부 하는 것(스파게티 코드)이 아닌,
여러 개의 처리 객체들(handler)로 나누고 이들을 사슬(chain)처럼 연결해 연쇄적으로 처리하는 행동 패턴
- 클라이언트의 요청에 대한 세세한 처리를 한 객체가 전부 하는 것(스파게티 코드)이 아닌,
- 명령 패턴(Command Pattern)
- 요청을 객체의 형태로 캡슐화하여 사용자가 보낸 요청을 나중에 이용할 수 있도록 재사용성을 높인 행동 패턴