โ† Kembali ke Design Pattern
๐Ÿ“‹
Behavioral

Template Method

Mendefinisikan kerangka algoritma di base class, sementara langkah-langkah tertentu diserahkan ke subclass.

Masalahnya

Beberapa class mengimplementasikan algoritma yang strukturnya sama tetapi langkahnya berbeda. Kode kerangka yang sama terduplikasi di setiap class.

Cara Kerja

  • โ€บBase class mendefinisikan kerangka algoritma, yaitu urutan langkah secara keseluruhan
  • โ€บSubclass meng-override langkah tertentu tanpa mengubah struktur keseluruhan
  • โ€บfinal pada template method mencegah subclass mengubah urutannya
  • โ€บHook method adalah override opsional yang menyediakan titik perluasan
  • โ€บHollywood Principle: "Don't call us, we'll call you", base class yang mengendalikan alurnya

Kapan Digunakan

โœ“Beberapa class berbagi struktur algoritma yang sama dan hanya beberapa langkahnya berbeda
โœ“Kode framework yang memanggil langkah buatan pengguna di titik tertentu
โœ“Menghilangkan duplikasi kode di antara class yang mirip
โœ“Pipeline pemrosesan data: fetch โ†’ parse โ†’ format โ†’ store

Contoh di Dunia Nyata

๐ŸŽ
iOS

UIViewController lifecycle (viewDidLoad, viewWillAppear, viewDidAppear), UIView draw(_:)

๐Ÿค–
Android

Fragment lifecycle (onCreate, onCreateView, onResume), Activity onCreate flow

๐ŸŒ
Web

React component lifecycle, Express route handler flow, Jest test lifecycle (beforeEach / afterEach)

Contoh Kode

Swift
class ReportGenerator {
    // Template method โ€” final so subclasses can't change the sequence
    final func generate() -> String {
        let data    = fetchData()
        let parsed  = parseData(data)
        let report  = formatReport(parsed)
        return report
    }

    func fetchData() -> String { "raw:server" }
    func parseData(_ raw: String) -> [String] { [raw] }
    func formatReport(_ items: [String]) -> String { items.joined(separator: "\n") }
}

class JSONReport: ReportGenerator {
    override func parseData(_ raw: String) -> [String] { ["JSON:\(raw)"] }
    override func formatReport(_ items: [String]) -> String {
        "{\(items.joined(separator: ","))}"
    }
}

class CSVReport: ReportGenerator {
    override func formatReport(_ items: [String]) -> String {
        items.joined(separator: ",")
    }
}

print(JSONReport().generate())  // {JSON:raw:server}
print(CSVReport().generate())   // raw:server