겨울 세일!
책임 연쇄

Go로 작성된 책임 연쇄

책임 연쇄 패턴은 핸들러 중 하나가 요청을 처리할 때까지 핸들러들의 체인​(사슬)​을 따라 요청을 전달할 수 있게 해주는 행동 디자인 패턴입니다.

이 패턴은 발신자 클래스를 수신자들의 구상 클래스들에 연결하지 않고도 여러 객체가 요청을 처리할 수 있도록 합니다. 체인은 표준 핸들러 인터페이스를 따르는 모든 핸들러와 런타임 때 동적으로 구성될 수 있습니다.

개념적인 예시

책임 연쇄 패턴을 병원 앱의 예시를 통해 살펴봅시다. 병원에는 다음과 같은 여러 부서가 있을 수 있습니다:

  • 접수처
  • 의사
  • 진료실
  • 계산대 직원

환자가 도착할 때마다 먼저 접수처에, 그다음에는 의사에게, 그다음에는 진료실에, 그다음에는 계산원​(등)​에게 이동합니다. 환자는 일련의 부서를 통해 보내지고 있으며, 각 부서의 기능이 완료될 때마다 환자를 사슬의 더 아래로 보냅니다.

이 패턴은 같은 요청을 처리할 후보가 여러 개일 때도 적용되며 또 요청을 처리할 수 있는 여러 객체가 있으므로 클라이언트가 수신자를 선택하지 않도록 할 때도 유용합니다. 또 다른 유용한 경우는 클라이언트와 수신기를 분리하려는 경우이며, 그러며 클라이언트는 체인의 첫 번째 요소만 알면 됩니다.

이 예시에서의 환자는 먼저 병원의 접수처에 갑니다. 그 후 접수처는 환자의 현재 상태에 따라 환자를 체인의 다음 핸들러로 보냅니다.

department.go: 핸들러 인터페이스

package main

type Department interface {
	execute(*Patient)
	setNext(Department)
}

reception.go: 구상 핸들러

package main

import "fmt"

type Reception struct {
	next Department
}

func (r *Reception) execute(p *Patient) {
	if p.registrationDone {
		fmt.Println("Patient registration already done")
		r.next.execute(p)
		return
	}
	fmt.Println("Reception registering patient")
	p.registrationDone = true
	r.next.execute(p)
}

func (r *Reception) setNext(next Department) {
	r.next = next
}

doctor.go: 구상 핸들러

package main

import "fmt"

type Doctor struct {
	next Department
}

func (d *Doctor) execute(p *Patient) {
	if p.doctorCheckUpDone {
		fmt.Println("Doctor checkup already done")
		d.next.execute(p)
		return
	}
	fmt.Println("Doctor checking patient")
	p.doctorCheckUpDone = true
	d.next.execute(p)
}

func (d *Doctor) setNext(next Department) {
	d.next = next
}

medical.go: 구상 핸들러

package main

import "fmt"

type Medical struct {
	next Department
}

func (m *Medical) execute(p *Patient) {
	if p.medicineDone {
		fmt.Println("Medicine already given to patient")
		m.next.execute(p)
		return
	}
	fmt.Println("Medical giving medicine to patient")
	p.medicineDone = true
	m.next.execute(p)
}

func (m *Medical) setNext(next Department) {
	m.next = next
}

cashier.go: 구상 핸들러

package main

import "fmt"

type Cashier struct {
	next Department
}

func (c *Cashier) execute(p *Patient) {
	if p.paymentDone {
		fmt.Println("Payment Done")
	}
	fmt.Println("Cashier getting money from patient patient")
}

func (c *Cashier) setNext(next Department) {
	c.next = next
}

patient.go

package main

type Patient struct {
	name              string
	registrationDone  bool
	doctorCheckUpDone bool
	medicineDone      bool
	paymentDone       bool
}

main.go: 클라이언트 코드

package main

func main() {

	cashier := &Cashier{}

	//Set next for medical department
	medical := &Medical{}
	medical.setNext(cashier)

	//Set next for doctor department
	doctor := &Doctor{}
	doctor.setNext(medical)

	//Set next for reception department
	reception := &Reception{}
	reception.setNext(doctor)

	patient := &Patient{name: "abc"}
	//Patient visiting
	reception.execute(patient)
}

output.txt: 실행 결과

Reception registering patient
Doctor checking patient
Medical giving medicine to patient
Cashier getting money from patient patient

다른 언어로 작성된 책임 연쇄

C#으로 작성된 책임 연쇄 C++로 작성된 책임 연쇄 자바로 작성된 책임 연쇄 PHP로 작성된 책임 연쇄 파이썬으로 작성된 책임 연쇄 루비로 작성된 책임 연쇄 러스트로 작성된 책임 연쇄 스위프트로 작성된 책임 연쇄 타입스크립트로 작성된 책임 연쇄