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 메서드를 호출하여 요청을 전송합니다.