โ† Kembali ke Design Pattern
โ›“๏ธ
Behavioral

Chain of Responsibility

Meneruskan request melalui rantai handler; setiap handler memutuskan apakah akan menanganinya atau meneruskannya.

Masalahnya

Beberapa objek mungkin bisa menangani sebuah request, tetapi kamu tidak tahu yang mana sebelumnya. Kamu ingin menghindari keterikatan pengirim dengan satu penerima tertentu.

Cara Kerja

  • โ€บSetiap handler menyimpan referensi ke handler berikutnya dalam rantai
  • โ€บHandler menangani request itu sendiri atau meneruskannya ke handler berikutnya
  • โ€บPengirim tidak perlu tahu handler mana yang akan memproses request
  • โ€บHandler bisa ditambah, dihapus, atau diurutkan ulang saat runtime
  • โ€บRequest bisa saja tidak tertangani jika tidak ada handler yang memprosesnya; tentukan perilaku default

Kapan Digunakan

โœ“Lebih dari satu handler bisa memproses request (pipeline middleware)
โœ“Handler yang dipakai harus ditentukan saat runtime
โœ“Pengecekan izin, rantai validasi, event bubbling
โœ“Pipeline logging, request interceptor

Contoh di Dunia Nyata

๐ŸŽ
iOS

UIResponder chain (touch events bubble up from subview to window), URLProtocol subclasses

๐Ÿค–
Android

OkHttp Interceptor chain, View.onTouchEvent propagation, Compose event handling

๐ŸŒ
Web

Express.js middleware (next()), Koa.js, DOM event bubbling, NestJS guards/interceptors

Contoh Kode

Swift
protocol RequestHandler: AnyObject {
    var next: RequestHandler? { get set }
    func handle(request: Int) -> String?
}

class LowHandler: RequestHandler {
    var next: RequestHandler?
    func handle(request: Int) -> String? {
        guard request > 10 else { return "Low handled \(request)" }
        return next?.handle(request: request)
    }
}

class MediumHandler: RequestHandler {
    var next: RequestHandler?
    func handle(request: Int) -> String? {
        guard request > 50 else { return "Medium handled \(request)" }
        return next?.handle(request: request)
    }
}

class HighHandler: RequestHandler {
    var next: RequestHandler?
    func handle(request: Int) -> String? { "High handled \(request)" }
}

let low = LowHandler(); let med = MediumHandler(); let high = HighHandler()
low.next = med; med.next = high

print(low.handle(request: 5)!)   // "Low handled 5"
print(low.handle(request: 30)!)  // "Medium handled 30"
print(low.handle(request: 99)!)  // "High handled 99"