✅ Chain of Responsibility (책임 연쇄) 패턴
🎯 의도 (Intent)
- 요청을 처리할 수 있는 객체를 하나로 고정하지 않고,
여러 객체가 연쇄적으로 연결되어 순차적으로 처리 기회를 갖도록 하는 패턴입니다.
- 요청을 보내는 측과 요청을 처리하는 측을 느슨하게 결합(loose coupling)시킵니다.
- 클라이언트는 누가 요청을 처리할지 알 필요가 없으며,
체인의 어느 객체가 처리할지 동적으로 결정됩니다.
👉 즉, 요청 처리 책임을 여러 객체에 분산시켜 유연하고 확장 가능한 처리 구조를 만든다.
🧩 구성 요소 (Participants)
-
Handler (추상 처리자)
- 요청을 처리할 인터페이스를 정의합니다.
- 다음 처리자를 가리키는 참조(nextHandler)를 보유하여 체인을 구성합니다.
- 요청을 처리할 수 없으면 다음 처리자에게 위임합니다.
-
ConcreteHandler (구체 처리자)
Handler를 구현하여 자신이 처리 가능한 요청이면 처리하고,
그렇지 않으면 다음 처리자에게 요청을 전달합니다.
- 체인의 일부로 동작하며 각기 다른 처리 로직을 가질 수 있습니다.
-
Client (클라이언트)
- 요청을 체인의 첫 번째 처리자에게 전달합니다.
- 어떤 처리자가 요청을 처리할지 알 필요가 없습니다.
📌 작동 방식
-
클라이언트 → 체인의 첫 번째 Handler에게 요청을 보냄
-
각 Handler는 요청을 검사
- 처리 가능 → 요청 처리 후 종료
- 처리 불가 → 다음
Handler로 전달
-
체인의 끝까지 처리자가 없으면 요청은 처리되지 않음
✅ Command (명령) 패턴
🎯 의도 (Intent)
- 요청(동작)을 객체로 캡슐화하여,
요청을 매개변수화, 저장, 실행 취소(undo), 재실행(redo)할 수 있도록 하는 패턴입니다.
- 실행될 작업(메서드 호출)과 요청을 발행하는 객체(클라이언트)를 분리(decouple)합니다.
- 요청을 실행하는 방법을 변경하지 않고 동작의 큐잉, 로깅, 트랜잭션 처리 등이 가능합니다.
👉 즉, 명령(요청)을 하나의 객체로 만들어서 요청의 발송자와 수신자를 분리하고,
실행 시점이나 실행 방법을 유연하게 관리할 수 있게 해줍니다.
🧩 구성 요소 (Participants)
-
Command (명령 인터페이스)
- 실행될 동작을 캡슐화하는 인터페이스를 정의합니다.
- 보통
execute() 메서드를 선언합니다.
-
ConcreteCommand (구체 명령)
Command 인터페이스를 구현합니다.
- 실제 요청을 수행할 수신자(Receiver)를 참조하고,
그 수신자의 메서드를 호출하여 작업을 수행합니다.
-
Receiver (수신자)
- 실제 작업을 수행하는 객체입니다.
- 명령이 전달되면 실질적인 비즈니스 로직을 실행합니다.
-
Invoker (호출자)
Command 객체를 저장하고 필요할 때 execute()를 호출합니다.
- 여러 명령을 큐에 넣거나, 실행 취소/재실행 로직을 관리할 수 있습니다.
-
Client (클라이언트)
ConcreteCommand 객체를 생성하고 수신자(Receiver)를 연결합니다.
Invoker에 명령 객체를 전달하여 실행을 트리거합니다.
📌 작동 방식
- Client는 특정 작업을 수행할
ConcreteCommand 객체를 생성하고, Receiver를 설정합니다.
- Invoker는 명령 객체를 저장하거나 요청 시
execute()를 호출합니다.
ConcreteCommand는 내부적으로 Receiver의 실제 동작을 호출하여 작업을 수행합니다.
✅ Interpreter (인터프리터) 패턴
🎯 의도 (Intent)
- 특정 언어나 문법에 대한 해석기를 정의하여,
문장을 해당 언어의 문법에 따라 해석하고 실행할 수 있도록 하는 패턴입니다.
- 문법 규칙을 클래스 계층으로 표현하고, 각 규칙을 객체화하여 문장을 해석합니다.
- 새로운 문법 규칙을 쉽게 추가할 수 있으며, 언어의 문법 구조를 유연하게 확장할 수 있습니다.
👉 즉, 언어의 문법을 클래스로 표현하고, 해당 문법을 해석할 수 있는 구조를 제공하여
간단한 언어나 명령어 집합을 해석할 때 유용합니다.
🧩 구성 요소 (Participants)
-
AbstractExpression (추상 표현식)
- 해석(interpret) 작업을 위한 인터페이스를 정의합니다.
- 모든 구체 표현식(terminal/non-terminal)이 이를 구현합니다.
-
TerminalExpression (종단 표현식)
- 문법의 기본 단위(터미널 심볼)를 해석하는 클래스입니다.
- 예: 숫자, 변수, 리터럴 등.
-
NonTerminalExpression (비종단 표현식)
- 다른 표현식들을 조합하여 더 복잡한 문법 규칙을 정의합니다.
- 예: 덧셈, 뺄셈, 조건식 등 연산자를 해석하는 클래스.
-
Context (문맥)
- 해석 과정에서 필요한 전역 정보(환경, 변수 값, 심볼 테이블 등)를 저장하고 제공합니다.
-
Client (클라이언트)
- 문법 규칙에 맞는 문장을 구문 트리(abstract syntax tree, AST) 형태로 작성하고,
해당 트리의 interpret() 메서드를 호출하여 해석을 수행합니다.
📌 작동 방식
- Client는 해석할 문장을 구문 트리로 구성합니다.
- 구문 트리의 각 노드는
AbstractExpression을 구현한 객체입니다.
- 클라이언트가 루트 표현식의
interpret(context)를 호출하면,
트리의 각 노드가 재귀적으로 해석 작업을 수행합니다.
✅ Iterator (반복자) 패턴
🎯 의도 (Intent)
- 집합 객체(Aggregate)의 내부 구조를 노출하지 않고,
그 요소들에 순차적으로 접근할 수 있는 방법을 제공합니다.
- 컬렉션의 순회 로직을 별도의 객체(
Iterator)로 분리하여,
여러 방식의 순회를 쉽게 구현할 수 있습니다.
👉 즉, 컬렉션 내부 구조를 숨기면서도 통일된 인터페이스로 요소를 순차적으로 접근하도록 합니다.
🧩 구성 요소 (Participants)
-
Iterator (반복자 인터페이스)
- 요소를 순차적으로 접근하는 인터페이스를 정의합니다.
- 보통
hasNext(), next() 같은 메서드를 포함합니다.
-
ConcreteIterator (구체 반복자)
Iterator 인터페이스를 구현하여 집합 객체의 현재 위치를 추적하고,
실제 순회 로직을 수행합니다.
-
Aggregate (집합체 인터페이스)
- 반복자를 생성하는 인터페이스를 정의합니다.
- 보통
createIterator() 메서드를 가집니다.
-
ConcreteAggregate (구체 집합체)
Aggregate 인터페이스를 구현합니다.
- 자신이 관리하는 컬렉션에 대해 ConcreteIterator를 생성하여 반환합니다.
-
Client (클라이언트)
Aggregate로부터 Iterator를 받아 요소를 순차적으로 접근합니다.
- 컬렉션의 내부 구현을 알 필요 없이 Iterator의 메서드만 사용합니다.
📌 작동 방식
- Client는
ConcreteAggregate에서 createIterator()를 호출해 Iterator를 얻습니다.
Iterator는 내부적으로 현재 위치를 추적하며, hasNext()와 next()를 통해 요소를 하나씩 반환합니다.
- 클라이언트는 컬렉션 구조를 몰라도 안전하게 순회할 수 있습니다.
🎯 의도 (Intent)
- 객체 간의 복잡한 상호작용을 캡슐화하여,
객체들이 서로를 직접 참조하지 않고 중재자(Mediator)를 통해서만 소통하도록 만드는 패턴입니다.
- 객체 간의 의존성을 줄이고(느슨한 결합), 상호작용 로직을 한 곳에 모아 유지보수성을 높입니다.
👉 즉, 여러 객체 간의 복잡한 관계를 하나의 중재자 객체로 캡슐화하여
객체들이 서로 독립적으로 존재하면서도 협력할 수 있게 합니다.
🧩 구성 요소 (Participants)
-
- 동료(Colleague) 객체 간의 상호작용을 캡슐화하는 인터페이스를 정의합니다.
- 보통
notify(sender, event)와 같은 메서드를 가집니다.
-
Mediator 인터페이스를 구현합니다.
- 여러 Colleague 간의 의사소통 로직을 중앙에서 관리하며,
특정 이벤트가 발생하면 적절한 Colleague에 메시지를 전달합니다.
-
Colleague (동료 클래스, 컴포넌트)
Mediator를 참조하여 다른 객체와 통신합니다.
- 서로 직접 참조하지 않고, 모든 요청을
Mediator를 통해 전달합니다.
-
ConcreteColleague (구체 동료 클래스)
Colleague를 구현하며,
자신의 상태 변경이나 이벤트를 Mediator에 알리고,
Mediator로부터 명령이나 메시지를 받아 동작합니다.
-
Client (클라이언트)
ConcreteMediator를 생성하고, Colleague 객체들을 Mediator와 연결합니다.
- 실제 상호작용은 Mediator를 통해 이루어집니다.
📌 작동 방식
- Client는 여러
ConcreteColleague와 ConcreteMediator를 생성하고 연결합니다.
ConcreteColleague가 이벤트를 발생시키면, 이를 Mediator에 알립니다.
Mediator는 다른 적절한 Colleague에게 메시지를 전달하거나 명령을 내립니다.
- Colleague들은 서로 직접 참조하지 않고 Mediator만 통해 상호작용합니다.
✅ Memento (메멘토) 패턴
🎯 의도 (Intent)
- 객체의 이전 상태를 저장하고 필요할 때 복원(restore)할 수 있도록 하는 패턴입니다.
- 객체의 내부 상태를 캡슐화하여 저장하면서도,
캡슐화를 위반하지 않고 외부에서 상태를 직접 접근하지 못하도록 합니다.
- 주로 실행 취소(Undo), 되돌리기(Redo), 버전 관리 기능을 구현할 때 사용됩니다.
👉 즉, 객체의 상태를 안전하게 저장해 두었다가
필요할 때 이전 상태로 복원할 수 있는 메커니즘을 제공합니다.
🧩 구성 요소 (Participants)
-
Memento (메멘토)
- Originator(원본 객체)의 내부 상태를 저장하는 객체입니다.
- 외부에는 상태 세부사항을 노출하지 않으며,
Originator만이 이 객체의 상태를 읽거나 복원할 수 있습니다.
-
Originator (원본 객체)
- 자신의 현재 상태를
Memento 객체에 저장하고,
필요할 때 Memento를 통해 상태를 복원합니다.
createMemento()와 restoreMemento(memento) 같은 메서드를 가집니다.
-
Caretaker (관리자)
Memento 객체를 보관하지만, 그 내부 상태에는 접근할 수 없습니다.
- 여러 개의 Memento를 저장하여 Undo/Redo 스택을 구현할 수도 있습니다.
-
Client (클라이언트)
- Originator와 Caretaker를 사용하여 상태 저장 및 복원을 수행합니다.
📌 작동 방식
- Originator가 현재 상태를 캡슐화한
Memento를 생성합니다.
- Caretaker는 이
Memento를 저장하지만 상태 세부 정보는 알 수 없습니다.
- 복원이 필요할 때, Caretaker가 저장된 Memento를 Originator에 전달합니다.
- Originator는 해당 Memento의 정보를 사용하여 상태를 이전 시점으로 복원합니다.
✅ Observer (옵서버) 패턴
🎯 의도 (Intent)
- 한 객체(Subject)의 상태 변화를 여러 다른 객체(Observers)에게
자동으로 알리고, 동기화할 수 있도록 하는 패턴입니다.
- 객체 간의 일대다(1\:N) 관계를 정의하여,
Subject가 변경되면 모든 Observer가 자동으로 갱신됩니다.
- Subject와 Observer 간의 결합도를 낮추고, 확장성을 높입니다.
👉 즉, 어떤 객체의 상태 변화가 있을 때,
연결된 다른 객체들이 자동으로 통보받아 반응할 수 있도록 합니다.
🧩 구성 요소 (Participants)
-
Subject (주제, 발행자)
- 옵서버를 등록(
attach)하거나 제거(detach)하는 메서드를 정의합니다.
- 상태가 변경되면 모든 옵서버에게 알림(
notify)을 전송합니다.
-
ConcreteSubject (구체 주제)
Subject를 구현하고, 실제 상태를 보유합니다.
- 상태 변경 시
notify()를 호출하여 옵서버들에게 알립니다.
-
Observer (옵서버 인터페이스)
- Subject로부터 알림을 받기 위한
update() 메서드를 정의합니다.
-
ConcreteObserver (구체 옵서버)
Observer 인터페이스를 구현합니다.
- Subject의 상태 변경 알림을 받아 자신의 상태를 갱신합니다.
-
Client (클라이언트)
- Subject와 Observer들을 생성하고 관계를 설정합니다.
📌 작동 방식
- Client는
ConcreteSubject와 하나 이상의 ConcreteObserver를 생성합니다.
- 옵서버들은
Subject에 자신을 등록(attach)합니다.
ConcreteSubject의 상태가 변경되면 notify()를 통해 모든 옵서버에 알립니다.
- 각
ConcreteObserver는 update()를 호출받아 자동으로 상태를 갱신합니다.
✅ State (상태) 패턴
🎯 의도 (Intent)
- 객체의 내부 상태에 따라 행동(behavior)이 달라지도록 하는 패턴입니다.
- 상태별 로직을 별도의 상태 클래스로 캡슐화하여,
객체가 상태 전환 시 클래스를 교체하는 방식으로 행동을 변경합니다.
if-else나 switch문으로 상태를 분기하는 대신,
상태 객체에 위임하여 유연하고 확장 가능한 상태 전환 로직을 제공합니다.
👉 즉, 객체의 상태 변화를 객체화하여
상태에 따른 행동 변화를 자연스럽게 처리할 수 있게 합니다.
🧩 구성 요소 (Participants)
-
Context (문맥 클래스)
- 현재 상태 객체(
State)를 유지하고,
상태 관련 요청을 현재 상태 객체에 위임합니다.
- 상태 전환 시 내부적으로
State 객체를 교체합니다.
-
State (상태 인터페이스)
- Context에서 호출할 상태별 행동 메서드를 정의합니다.
- 예:
handle(), request() 등의 메서드.
-
ConcreteState (구체 상태 클래스)
State 인터페이스를 구현하여,
특정 상태에서의 행동 로직을 정의합니다.
- 필요 시 Context의 상태를 다른 상태 객체로 변경할 수 있습니다.
-
Client (클라이언트)
- Context 객체를 사용하며, 상태 전환은 Context 내부에서 처리되므로
클라이언트는 상태 변경 로직을 알 필요가 없습니다.
📌 작동 방식
- Client는 Context 객체를 생성하고 초기 상태를 설정합니다.
- Context가 요청을 받으면 현재
State 객체의 메서드에 위임합니다.
ConcreteState는 행동을 수행하고, 필요 시 Context의 상태를 다른 State로 변경합니다.
- 상태 전환이 일어나도 클라이언트 코드에는 변경이 필요 없습니다.
✅ Strategy (전략) 패턴
🎯 의도 (Intent)
- 알고리즘(행동) 군(群)을 정의하고, 각각을 캡슐화하여
상호 교환 가능하게 만드는 패턴입니다.
- 클라이언트는 런타임에 알고리즘을 선택하거나 교체할 수 있으며,
알고리즘의 변경이 클라이언트 코드에 영향을 주지 않습니다.
if-else나 switch문으로 여러 알고리즘을 분기하는 대신,
전략 객체(Strategy)를 위임하여 유연한 설계를 제공합니다.
👉 즉, 동일한 문제를 해결하는 여러 알고리즘을 정의하고,
필요에 따라 쉽게 교체할 수 있도록 만드는 패턴입니다.
🧩 구성 요소 (Participants)
-
Strategy (전략 인터페이스)
- 알고리즘(행동)을 수행하는 공통 인터페이스를 정의합니다.
- 예:
execute(), sort(), calculate() 등의 메서드.
-
ConcreteStrategy (구체 전략 클래스)
Strategy 인터페이스를 구현하여 특정 알고리즘 로직을 제공합니다.
- 서로 다른 알고리즘이 여러 개 존재할 수 있으며, 필요에 따라 교체됩니다.
-
Context (문맥 클래스)
Strategy 객체를 참조하고,
특정 작업을 수행할 때 현재 설정된 Strategy 객체에 알고리즘 실행을 위임합니다.
- 전략을 런타임에 교체할 수 있습니다.
-
Client (클라이언트)
- 사용할
ConcreteStrategy를 선택하여 Context에 전달합니다.
- 알고리즘의 구체적인 구현은 몰라도 됩니다.
📌 작동 방식
- Client가 사용할 알고리즘(ConcreteStrategy)을 선택하고, Context에 주입합니다.
- Context는 요청을 받을 때 알고리즘 실행을 현재
Strategy 객체에 위임합니다.
- 전략을 교체하면 Context의 동작 방식도 자연스럽게 변경됩니다.
✅ Template Method (템플릿 메서드) 패턴
🎯 의도 (Intent)
- 알고리즘의 골격(템플릿)을 정의하고,
알고리즘의 일부 단계를 서브클래스에서 재정의(override)할 수 있도록 하는 패턴입니다.
- 알고리즘의 구조는 상위 클래스에 두고, 세부 단계는 하위 클래스에서 구현하여
코드 재사용성을 높이고 알고리즘 변형을 쉽게 만듭니다.
- 상위 클래스는 알고리즘의 전체 흐름을 제어하면서,
하위 클래스에 구체적 세부 동작만 위임합니다.
👉 즉, 공통 로직은 상위 클래스에, 변화되는 부분은 하위 클래스에서 구현하도록 하여
알고리즘의 일관성을 유지하면서 확장을 용이하게 합니다.
🧩 구성 요소 (Participants)
-
AbstractClass (추상 클래스)
- 템플릿 메서드(Template Method)를 정의하며,
알고리즘의 전체 흐름(단계)을 구현합니다.
- 일부 단계는 추상 메서드(abstract method) 또는 hook 메서드로 선언하여
서브클래스가 구체적으로 구현하도록 합니다.
-
ConcreteClass (구체 클래스)
AbstractClass에서 정의한 추상 메서드들을 구현하여
알고리즘의 특정 단계를 구체적으로 수행합니다.
-
Client (클라이언트)
AbstractClass의 인터페이스를 사용하여 알고리즘을 실행합니다.
- 알고리즘의 흐름은 동일하지만, 구체적 동작은 하위 클래스에 의해 달라집니다.
📌 작동 방식
- Client는
AbstractClass를 참조하여 템플릿 메서드를 호출합니다.
- 템플릿 메서드는 알고리즘의 전체적인 절차를 고정해 놓고,
일부 단계의 세부 구현은 ConcreteClass에서 제공됩니다.
- 하위 클래스가 바뀌더라도 템플릿의 전체 구조는 변경되지 않습니다.
✅ Visitor (방문자) 패턴
🎯 의도 (Intent)
- 객체 구조(요소들)를 변경하지 않고,
객체들에 대해 수행할 새로운 연산(기능)을 추가할 수 있도록 하는 패턴입니다.
- 데이터 구조(요소 클래스)와 연산(Visitor)을 분리하여,
기능 확장이 용이하고, 요소 클래스의 수정 없이 새로운 연산을 추가할 수 있습니다.
- 기존 클래스에 연산을 추가하기 위해 클래스를 수정하는 문제(개방-폐쇄 원칙 위배)를 방지합니다.
👉 즉, 요소 클래스는 그대로 두고,
방문자 객체(Visitor)를 통해 새로운 동작을 외부에서 주입할 수 있도록 합니다.
🧩 구성 요소 (Participants)
-
Visitor (방문자 인터페이스)
- 각 요소(Element) 타입에 대해 방문할 메서드를 정의합니다.
- 예:
visitConcreteElementA(), visitConcreteElementB().
-
ConcreteVisitor (구체 방문자)
Visitor 인터페이스를 구현하여,
각 요소별로 수행할 실제 연산을 정의합니다.
-
Element (요소 인터페이스)
- 방문자를 받아들이기 위한
accept(visitor) 메서드를 정의합니다.
- 이 메서드는 방문자를 호출하여 자신의 타입에 맞는
visit 메서드를 실행하게 합니다.
-
ConcreteElement (구체 요소 클래스)
Element를 구현하고, accept(visitor)에서 visitor.visitConcreteElement(this)를 호출합니다.
- 방문자에게 자신을 전달하여, 방문자가 해당 요소에 맞는 연산을 수행하도록 합니다.
-
ObjectStructure (객체 구조)
- 여러 요소 객체들을 포함하거나 관리합니다.
- 방문자를 받아 모든 요소에 대해 순회하며
accept(visitor)를 호출합니다.
-
Client (클라이언트)
Visitor와 ObjectStructure를 생성하고,
방문자를 요소 집합에 적용하여 원하는 연산을 수행합니다.
📌 작동 방식
- Client는
ConcreteVisitor를 생성하고 ObjectStructure에 전달합니다.
ObjectStructure는 내부 요소들을 순회하며 각 요소의 accept(visitor)를 호출합니다.
- 요소는 자신을
visitor에게 넘겨주며, visitor는 해당 요소 타입에 맞는 연산을 실행합니다.
- 새로운 연산을 추가할 때는 새로운 Visitor만 추가하면 되며, 기존 요소 클래스는 수정할 필요가 없습니다.