apple/DesignPattern, Architecture
Swift 디자인패턴 Chain-of-Responsibility Pattern (책임 연쇄 패턴)
lgvv
2022. 7. 5. 19:13
Swift 디자인패턴 Chain-of-Responsibility Pattern (책임 연쇄 패턴)
Chain of Responsibility 패턴은 요청을 처리할 수 있는 여러 객체를 연결하여, 요청이 처리될 수 있는 객체를 찾는 행동 패턴.
요청을 보낸 객체와 요청을 처리하는 객체를 분리하여, 요청을 처리할 수 있는 객체가 여러 개일 때 유용
히스토리
- 2022-07-05: 디자인 패턴 스터디 정리
- 2024-11-26: 포스팅 글 재정리 및 스스로 만든 예제로 변경
Chain-of-Responsibility Pattern
Chain-of-Responsibility Pattern은 일반적으로 3개지 개념으로 구성됨
- Handler Protocol: 요청을 처리할 수 있는 인터페이스
- Concrete Handler: 요청을 처리하는 구현 클래스. 각 핸들러는 다음에 위치한 핸들러 참조할 수 있음
- Client: 요청을 생성하고, 핸들러 체인에 요청 전달
책임 연쇄 패턴 적용을 고려할 수 있는 상황
- 텍스트의 형식을 변경하는 여러 처리기를 연결해, 각 처리기가 요청을 처리할 수 있도록 함.
- GUI 이벤트 처리, 로그 처리, 다양한 요청을 처리하는 시스템에서 유용
- 요청을 보낸 객체와 요청을 처리하는 객체를 분리해, 요청 처리의 유연성을 높이고자 할 경우
책임 연쇄 패턴 장점
- 유연성: 요청 핸들러의 경로를 동적으로 변경할 수 있을때 유용
- OCP: 기존 핸들러의 수정 없이 새로운 핸들러를 쉽게 추가할 수 있음
- SRP: 각 핸들러는 단일 책임 원칙을 준수
책임 연쇄 패턴 단점
- 디버깅 어려움: 요청을 처리하는 곳이 런타임에 결정되기 때문에 추적하기 어려움
- 성능 문제: 요청이 여러 핸들러를 거쳐야함으로 성능 저하가 발생할 수 있음
코드 예제
에러 로그 예제를 만들어보고자 함. 최근 WWDC에서 발표한 Logger(os_log)와 비슷
import SwiftUI
// 핸들러 프로토콜
protocol Handler {
var successor: Handler? { get set }
func handle(level: Level, message: String)
}
enum Level {
case info
case error
case warning
case debug
var stringValue: String {
switch self {
case .info: return "INFO"
case .error: return "ERROR"
case .warning: return "WARNING"
case .debug: return "DEBUG"
}
}
}
// 정보 로그 핸들러
class InfoHandler: Handler {
var successor: Handler?
func handle(level: Level, message: String) {
if level == .info {
print("INFO: \(message)")
} else {
successor?.handle(level: level, message: message)
}
}
}
// 경고 로그 핸들러
class WarningHandler: Handler {
var successor: Handler?
func handle(level: Level, message: String) {
if level == .warning {
print("WARNING: \(message)")
} else {
successor?.handle(level: level, message: message)
}
}
}
// 오류 로그 핸들러
class ErrorHandler: Handler {
var successor: Handler?
func handle(level: Level, message: String) {
if level == .warning {
print("ERROR: \(message)")
} else {
successor?.handle(level: level, message: message)
}
}
}
private struct ContentView: View {
var body: some View {
Button("Execute") {
// 핸들러 체인 구성
let errorHandler = ErrorHandler()
let warningHandler = WarningHandler()
warningHandler.successor = errorHandler
let infoHandler = InfoHandler()
infoHandler.successor = warningHandler
// 로그 메시지 처리
infoHandler.handle(level: .info, message: "This is an info message.")
infoHandler.handle(level: .warning, message: "This is a warning message.")
infoHandler.handle(level: .error, message: "This is an error message.")
infoHandler.handle(level: .debug, message: "This is a debug message.") // 처리되지 않음
}
}
}
#Preview {
ContentView()
}
(참고)
https://refactoring.guru/ko/design-patterns/chain-of-responsibility