🎈 체인 패턴 (Chain of Responsibility)
• 책임 전가(고리, 연쇄)라고 불리는 패턴
• 처리할 수 있는 다른 객체 연결
→ 요청을 처리하거나 못해도 다음 객체로 전달한다.
• 요청 자체와 각 처리 객체 사이의 결합을 피한다.
→ 객체 메시지 송신과 수신 분리
• 하나의 객체에서 모든 처리를 구현하지 않을 수 있다.
→ 객체의 의존성 주입을 통한 위임
• 디자인 패턴에서 행위 패턴에 속한다.
💻 디자인 패턴(Design Pattern)이란?
👨💻 디자인 패턴(Design Pattern)이란? • SW 개발 방법 중에서도 구조적인 문제 해결에 목적을 둔다. • 알고리즘과 같이 특정 문제를 해결하는 Logic 형태보다는 특정 상황에 적용할 수 있는 방
zoosso.tistory.com
객체 지향 프로그래밍 5대 원칙 [SOLID]
객체지향 프로그래밍에는 「SOLID」 원칙이 있다. 유연하고 확장성이 있는 코드 재사용에 목적을 둔다. • SRP (Single Responsibility Principle, 단일책임) • OCP (Open-Closed Principle, 개방-폐쇄 원칙) • LSP (L
zoosso.tistory.com
[체인 패턴 예제]
#include <iostream>
struct Handler
{
Handler* next = nullptr;
void Handle(int issue)
{
// 처리 가능한 경우
if (Process(issue))
{
std::cout << " ok" << std::endl;
return;
}
// 처리하지 못하고, 다음 처리 객체가 남아 있는 경우
if (next != nullptr)
next->Handle(issue);
}
virtual bool Process(int problem) = 0;
};
class MinusHandler : public Handler
{
public:
bool Process(int issue) override
{
std::cout << " Minus Handler -";
bool b = issue < 0; // 음수
return b;
}
};
class OddHandler : public Handler
{
public:
bool Process(int problem) override
{
std::cout << " Odd Handler -";
bool ret = problem % 2 == 1; // 홀수
return ret;
}
};
class EvenHandler : public Handler
{
public:
bool Process(int problem) override
{
std::cout << " Even Handler -";
bool ret = problem % 2 == 0; // 짝수
return ret;
}
};
int main()
{
MinusHandler minusHandle;
EvenHandler evenHandle;
OddHandler oddHandle;
minusHandle.next = &evenHandle;
evenHandle.next = &oddHandle;
oddHandle.next = nullptr;
minusHandle.Handle(-2);
minusHandle.Handle(10);
minusHandle.Handle(13);
}
Handler 역할로 Minus, Odd, Even 객체를 만들고 연결해주었다.
- 시작하는 Handler를 설정 가능
- 우선순위에 따라 처리되는 Handler 순서 설정 가능
- 새로운 Handler 객체를 만들어 연결 해주면 된다.
[예제 코드]
책임 연쇄 패턴 적용 X → 조건문 활용
#include <iostream>
#include <string>
class Logger {
public:
Logger(int level) : level(level) {}
void log(const std::string& message) {
if (level == 1 && Logger::logLevel >= 1) {
std::cout << "Error Logger: " << message << std::endl;
}
if (level == 2 && Logger::logLevel >= 2) {
std::cout << "File Logger: " << message << std::endl;
}
if (level == 3 && Logger::logLevel >= 3) {
std::cout << "Console Logger: " << message << std::endl;
}
}
static void setLogLevel(int level) {
logLevel = level;
}
private:
int level;
static int logLevel;
};
int Logger::logLevel = 3;
void main() {
Logger::setLogLevel(3);
Logger errorLogger(1);
Logger fileLogger(2);
Logger consoleLogger(3);
errorLogger.log("This is an error message.");
fileLogger.log("This is a file log message.");
consoleLogger.log("This is a console log message.");
}
책임 연쇄를 통해 각 Logger에 Error Message를 출력할 수 있다.
각 객체가 단일 책임을 가지게 되었는데
새로운 Logger 유형 추가된다면 수정하기 쉬워졌다.
🎈 체인 패턴 장단점
+ 연쇄 구성에 따라 동적으로 처리자 변경/확장할 때 유용
+ 객체간 느슨한 결합 (객체 변경시 영향도 최소화)
+ 단일 책임 원칙 준수: 각 처리자는 하나의 책임을 갖도록 설계
- 순차적으로 객체를 처리하기 다소 지연 시간 발생
- 요청이 처리 과정을 따라가지 않을 수 있으며 예측하기 어려울 수 있음
- 적절한 종료 조건이 없으면 무한 Loop에 빠질 수 있음
🎈 활용 예시
Event 처리 시스템: GUI 라이브러리나 WEB 이벤트 처리와 같이 다양한 이벤트 Handler 처리
Log 처리: 각 로그 메시지의 유형에 따른 처리
보안 시스템: 보안 규칙에 따른 권한 부여
미들웨어: 서버에 도달하기 전에 다양한 처리 가능
[예제 코드]
ATM에서 지출 요청을 처리
#include <iostream>
#include <string>
class Request {
public:
Request(int amount) : amount(amount) {}
int getAmount() const { return amount; }
void setAmount(int _amount) { amount = _amount; }
private:
int amount;
};
class Handler {
public:
Handler(Handler* successor = nullptr) : successor(successor) {}
virtual void handleRequest(Request& request) {
if (successor) {
successor->handleRequest(request);
}
}
void setSuccessor(Handler* successor) {
this->successor = successor;
}
protected:
Handler* successor;
};
class Company_B : public Handler {
public:
Company_B(Handler* successor = nullptr) : Handler(successor) {}
void handleRequest(Request& request) override {
std::cout << "[B]: OK! " << request.getAmount() << std::endl;
}
};
class Company_A : public Handler {
public:
Company_A(Handler* successor = nullptr) : Handler(successor) {}
void handleRequest(Request& request) override {
if (request.getAmount() <= 100) {
std::cout << "[A]: OK! " << request.getAmount() << std::endl;
}
else {
std::cout << "[A]: Sorry... -> ";
successor->handleRequest(request);
}
}
};
void main() {
Company_B objB;
Company_A objA;
objA.setSuccessor(&objB);
Request request(90);
objA.handleRequest(request);
request.setAmount(150);
objA.handleRequest(request);
}
amount 100 이하는 Company_A에서 처리할 수 있지만
그것보다 많은 수량은 Company_B에서 처리 가능하다.
🎈 다른 디자인 패턴과 비교
객체를 감싸서 객체에 새로운 기능을
동적으로 추가하는데 사용되는 패턴
[디자인패턴] 장식자 패턴 (Decorator)
🎈 데코레이터 패턴 (Decorator Pattern) • 객체에 동적으로 기능을 추가하거나 변경할 수 있게 해주는 패턴 • 압축, 암호화, 버퍼링 기능 추가시 활용해볼 수 있다. • 디자인 패턴 중 구조 패턴에
zoosso.tistory.com
• 전략 (Strategy)
특정 행동(알고리즘)을 캡슐화하고, 런타임에 알고리즘 교체
객체의 동작을 변경하려는 경우 사용
💻 [디자인패턴] 전략 패턴 (Strategy Pattern)
전략 패턴 (Strategy Pattern) 이란? 전략(Strategy)은 코드 내부에서 로직(Logic)을 처리하는 「알고리즘」 어떤 목적 달성을 위한 수행 방식이라고 생각하면 좋다. 영화관에서 이벤트 영화 예매 방식을
zoosso.tistory.com
명령을 캡슐화하고 수신자에 전달하여 실행
요청과 실행을 분리하려는 경우에 사용된다.
[디자인패턴] 커맨드 패턴 (Command Pattern)
🎈 커맨드 패턴 (Command Pattern) • 명령을 캡슐화하고 실행하기 위해 사용 • GUI 응용 프로그램, 트랜잭션 처리, 큐 관리 등에 활용 가능 • 명령 이력 관리, 역명령 실행(Undo), 동적 선택과 같은 상
zoosso.tistory.com
객체 상태가 변경될 때 관찰자에게 알려주면
그 변화를 다수의 객체에게 알리고자할 때 사용
[디자인 패턴] 관찰자(Observer) 패턴
🎈 감시자 패턴 (Observer Pattern) • 어떤 객체 상태가 변경되면 다른 객체(observer)에게 알리는 디자인 패턴 → 의존관계에 있는 모든 객체들이 통지받고 자동으로 갱신 → 1:多 형태로 Broadcast로 활
zoosso.tistory.com
'까망 동네 > 디자인 패턴' 카테고리의 다른 글
[디자인패턴] 어댑터 패턴 (Adapter Pattern) (8) | 2024.10.13 |
---|---|
💻 디자인 패턴(Design Pattern)이란? (6) | 2024.08.02 |
객체 지향 프로그래밍 5대 원칙 [SOLID] (40) | 2023.11.19 |
[디자인 패턴] 반복자 패턴(Iterator Pattern) (33) | 2023.11.14 |
[디자인패턴] 방문자 패턴 (Visitor Pattern) (3) | 2023.11.13 |
댓글