티스토리 뷰
반응형
책임연쇄 패턴 [ 행동 ]
핸들러들간의 체인에 따라 요청을 전달할 수 있게 해주는 행동 패턴
각 핸들러는 요청을 받으면 요청을 처리할지, 다음으로 전달할지를 결정한다.
주문시스템을 개발한다고 했을 때 초기 시스템의 동작은 순차적으로 흘러야했고 동작은 다음과 같았다.
- 주문확인
- 상품 수량확인
- 배송지 확인
- 주문 완료
시간이 지나자 각 흐름사이에 동작이 추가되어야하는 요구사항이 있었다.
- 주문확인
- 주문자 유효성확인
- 상품 수량확인
- 동일 요청 캐싱처리
- 배송지 확인
- 배송지 유효성확인
- 주문 완료
이런 요구사항을 만족시키기 위해 책임연쇄패턴을 이용하여 각 단계를 독립실행형 객체로 변환한다.
핸들러들을 체인으로 연결하고 각 핸들러에는 다음 핸들러에 대한 참조를 저장하기 위한 필드가 존재한다.
핸들러는 요청을 더 이상 전달하지 않고 중지시킬 수 있는 결정을 내릴 수 있다.
// Handler 인터페이스를 정의합니다.
interface Handler {
setNext(handler: Handler): Handler;
handle(request: any): any;
}
// 기본 핸들러 클래스입니다. 다른 핸들러들에 상속됩니다.
abstract class AbstractHandler implements Handler {
private nextHandler: Handler | null = null;
// 다음 핸들러를 설정합니다.
public setNext(handler: Handler): Handler {
this.nextHandler = handler;
return handler;
}
// 요청을 처리하고, 다음 핸들러가 있으면 다음 핸들러에 요청을 전달합니다.
public handle(request: any): any {
if (this.nextHandler) {
return this.nextHandler.handle(request);
}
return null;
}
}
// 각 핸들러 클래스를 정의합니다.
class OrderCheckHandler extends AbstractHandler {
public handle(request: any): any {
console.log('주문 확인');
return super.handle(request); // 다음 핸들러로 요청을 전달합니다.
}
}
class CustomerValidationHandler extends AbstractHandler {
public handle(request: any): any {
console.log('주문자 유효성 확인');
return super.handle(request); // 다음 핸들러로 요청을 전달합니다.
}
}
class StockCheckHandler extends AbstractHandler {
public handle(request: any): any {
console.log('상품 수량 확인');
return super.handle(request); // 다음 핸들러로 요청을 전달합니다.
}
}
class CacheRequestHandler extends AbstractHandler {
public handle(request: any): any {
console.log('동일 요청 캐싱 처리');
return super.handle(request); // 다음 핸들러로 요청을 전달합니다.
}
}
class AddressCheckHandler extends AbstractHandler {
public handle(request: any): any {
console.log('배송지 확인');
return super.handle(request); // 다음 핸들러로 요청을 전달합니다.
}
}
class AddressValidationHandler extends AbstractHandler {
public handle(request: any): any {
console.log('배송지 유효성 확인');
return super.handle(request); // 다음 핸들러로 요청을 전달합니다.
}
}
class OrderCompleteHandler extends AbstractHandler {
public handle(request: any): any {
console.log('주문 완료');
return super.handle(request); // 다음 핸들러로 요청을 전달합니다.
}
}
// 클라이언트 코드
const orderCheckHandler = new OrderCheckHandler();
const customerValidationHandler = new CustomerValidationHandler();
const stockCheckHandler = new StockCheckHandler();
const cacheRequestHandler = new CacheRequestHandler();
const addressCheckHandler = new AddressCheckHandler();
const addressValidationHandler = new AddressValidationHandler();
const orderCompleteHandler = new OrderCompleteHandler();
// 핸들러들을 체인으로 연결합니다.
orderCheckHandler
.setNext(customerValidationHandler)
.setNext(stockCheckHandler)
.setNext(cacheRequestHandler)
.setNext(addressCheckHandler)
.setNext(addressValidationHandler)
.setNext(orderCompleteHandler);
// 요청을 첫 번째 핸들러에 전달합니다.
orderCheckHandler.handle({});
장점
- 유연성: 요청을 처리하는 객체들을 쉽게 추가하거나 제거할 수 있음. 새로운 요청 처리 객체를 추가하거나 기존 객체를 제거하는 것이 간단함.
- 단일 책임 원칙(SRP) 준수: 각 객체는 하나의 작업만을 처리함. 이를 통해 코드의 가독성과 유지보수성이 향상됨.
- 확장성: 새로운 처리 단계를 추가할 때 기존 코드를 수정할 필요 없이 체인에 추가하기만 하면 됨. 시스템의 확장성을 높여줌.
- 클라이언트와 처리 객체의 분리: 클라이언트는 요청을 처리하는 객체들에 대해 알 필요가 없음. 클라이언트는 단지 체인의 첫 번째 객체에 요청을 전달하기만 하면 됨.
- 유연한 처리 순서: 처리 객체의 순서를 쉽게 변경할 수 있음. 다양한 처리 시나리오를 지원할 수 있음.
단점
- 디버깅 어려움: 체인 구조로 인해 디버깅이 어려울 수 있음. 요청이 어떤 객체에 의해 처리되었는지 추적하기가 복잡할 수 있음.
- 성능 문제: 요청이 체인의 끝까지 전달되는 경우, 많은 객체들을 거치면서 성능이 저하될 수 있음. 특히 체인이 길어질수록 더 큰 문제가 됨.
- 불확실한 처리: 모든 객체가 요청을 처리하지 않고 다음 객체로 전달할 수 있음. 요청이 반드시 처리된다는 보장이 없음. 요청이 체인의 끝에 도달할 때까지 처리되지 않을 수 있음.
- 복잡성 증가: 체인의 구조가 복잡해질수록 시스템의 전반적인 복잡성이 증가함. 이는 코드의 이해와 유지보수를 어렵게 만들 수 있음.
반응형
댓글
반응형
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
농담곰의 고군분투 개발기