1. 책임 연쇄 패턴이란
책임 연쇄 패턴은 요청의 발신자와 수신자를 분리하여 여러 객체가 요청을 처리할 기회를 부여하는 행위 디자인 패턴입니다. 각 수신자는 다른 수신자에 대한 참조를 포함하고 있으며, 요청을 처리할 수 없는 경우 해당 요청을 다음 수신자에게 전달하여 요청이 처리되거나 연쇄의 끝에 도달할 때까지 반복됩니다.
2. 책임 연쇄 패턴의 특성과 이점
책임 연쇄 패턴의 특성과 이점은 다음과 같습니다:
- 발신자와 수신자의 분리: 발신자는 어떤 수신자가 요청을 처리하는지 신경 쓸 필요가 없으며, 연쇄 내의 특정 핸들러를 알 필요도 없습니다.
- 유연성: 코드를 수정하지 않고도 연쇄 내의 핸들러를 동적으로 추가, 제거 또는 순서를 변경할 수 있습니다.
- 확장성: 새로운 특정 핸들러를 추가하여 책임 연쇄를 쉽게 확장할 수 있습니다.
- 단일 책임 원칙: 각 특정 핸들러는 자신의 처리 논리에 대해서만 신경쓰면 됩니다.
- 설정 가능성: 필요에 따라 핸들러 연쇄를 구성하여 다른 요청에 대해 다른 핸들러 연쇄를 갖도록 설정할 수 있습니다.
3. 책임 연쇄 패턴의 실제 응용 예
책임 연쇄 패턴은 웹 애플리케이션에서의 요청 처리, 에러 처리, 이벤트 처리 등 다양한 실제 응용에 사용될 수 있습니다:
- 웹 애플리케이션에서의 요청 처리: 신원 인증, 로깅, 권한 검증과 같은 다양한 유형의 요청을 처리하는 데 사용될 수 있습니다.
- 에러 처리: 각 핸들러가 특정 유형의 오류 처리에 책임을 지고 필요에 따라 오류를 다음 핸들러에 전달하는 데 사용될 수 있습니다.
- 이벤트 처리: 사용자 클릭 이벤트, 네트워크 요청 이벤트 등 다양한 유형의 이벤트를 처리하는 데 사용될 수 있습니다.
4. 고랭(Golang)에서 책임 연쇄 패턴의 구현
4.1 UML 클래스 다이어그램
4.2 예제 소개
위의 UML 클래스 다이어그램에서 추상 핸들러(Handler)와 두 가지 구체적 핸들러(ConcreteHandler1 및 ConcreteHandler2)를 정의했습니다. 클라이언트(Client)는 핸들러의 handleRequest 메서드를 호출하여 요청을 초기화합니다.
4.3 구현 단계 1: 추상 핸들러 인터페이스 정의
type Handler interface {
HandleRequest(request Request) error
SetNext(handler Handler)
}
type Request interface {
Condition bool
}
추상 핸들러 인터페이스는 요청 처리를 위한 HandleRequest 메서드와, 다음 핸들러를 설정하기 위한 SetNext 메서드를 정의합니다.
4.4 구현 단계 2: 구체적 핸들러 클래스 구현
type ConcreteHandler1 struct {
next Handler
}
func (h *ConcreteHandler1) HandleRequest(request Request) error {
// 요청 처리 로직
if request.Condition {
// 요청 처리를 위한 코드
return nil
} else {
if h.next != nil {
return h.next.HandleRequest(request)
}
return errors.New("핸들러를 찾을 수 없습니다")
}
}
func (h *ConcreteHandler1) SetNext(handler Handler) {
h.next = handler
}
type ConcreteHandler2 struct {
next Handler
}
func (h *ConcreteHandler2) HandleRequest(request Request) error {
// 요청 처리 로직
if request.Condition {
// 요청 처리를 위한 코드
return nil
} else {
if h.next != nil {
return h.next.HandleRequest(request)
}
return errors.New("핸들러를 찾을 수 없습니다")
}
}
func (h *ConcreteHandler2) SetNext(handler Handler) {
h.next = handler
}
구체적 핸들러 클래스는 추상 핸들러 인터페이스를 구현하고 HandleRequest 및 SetNext 메서드를 오버라이딩합니다.
4.5 구현 단계 3: 책임 연쇄 구성
handler1 := &ConcreteHandler1{}
handler2 := &ConcreteHandler2{}
handler1.SetNext(handler2)
구체적 핸들러를 인스턴스화하고 다음 핸들러를 설정하여 책임 연쇄를 구성합니다.
4.6 구현 단계 4: 클라이언트 코드
func main() {
handler := &ConcreteHandler1{}
// 책임 연쇄 구성
handler.SetNext(&ConcreteHandler2{})
// 요청 전송
handler.HandleRequest(Request{Condition: true})
}
클라이언트 코드에서는 구체적 핸들러를 인스턴스화하고 다음 핸들러를 설정한 후, handleRequest 메서드를 호출하여 요청을 전송합니다.