Pemrograman · Pola desain
Penjelasan pola Template Method beserta contohnya
Jawaban singkat
Template Method adalah pola desain behavioral yang mendefinisikan kerangka algoritma dalam method base class dan membiarkan subclass meng-override langkah tertentu tanpa mengubah urutan keseluruhan. Base class menentukan apa yang terjadi dan kapan; subclass menentukan bagaimana sebagian langkah dikerjakan. Langkah opsional dengan implementasi default disebut hook.
Tujuan dan masalah yang diselesaikan
Tujuan: mendefinisikan kerangka algoritma dalam sebuah operasi, dengan menunda beberapa langkah ke subclass. Template Method memungkinkan subclass mendefinisikan ulang langkah tertentu dari algoritma tanpa mengubah struktur algoritmanya. Ini salah satu pola behavioral dalam buku Gang of Four (GoF).
Bayangkan tool pelaporan yang mengekspor data sebagai CSV dan JSON. Kedua exporter melakukan hal yang sama dengan urutan yang sama: memuat baris, memeriksa apakah ada isinya, memformatnya, dan menambahkan footer berisi jumlah baris. Hanya pemformatannya yang berbeda. Jika tiap exporter ditulis terpisah, langkah yang sama disalin, dan perbaikan di satu exporter (misalnya penanganan hasil kosong yang lebih baik) mudah terlupa di yang lain.
Dengan Template Method, base class Exporter berisi method export dengan urutan langkah yang tetap. Langkah yang bervariasi berupa abstract method. CsvExporter dan JsonExporter hanya mengimplementasikan langkah-langkah itu.
Struktur dan peserta
| Peran | Tanggung jawab |
|---|---|
| Abstract class | Mengimplementasikan template method, yang memanggil langkah dalam urutan tetap; mendeklarasikan langkah abstrak dan dapat menyediakan hook |
| Template method | Method publik yang mendefinisikan algoritma; biasanya tidak untuk di-override |
| Primitive operation | Langkah abstrak yang harus diimplementasikan setiap subclass |
| Hook | Langkah dengan implementasi default (sering kosong) yang boleh di-override subclass |
| Concrete class | Mengimplementasikan primitive operation dan meng-override hook sesuai kebutuhan |
Desain ini membalik kendali: base class memanggil method subclass, bukan sebaliknya. Ini kadang disebut prinsip Hollywood: "jangan hubungi kami, kami yang akan menghubungi Anda".
Implementasi TypeScript
export adalah template method. format adalah primitive operation yang harus diimplementasikan subclass, dan header adalah hook dengan default kosong.
type Row = { name: string; score: number };
abstract class Exporter {
// The template method: fixed order of steps
export(rows: Row[]): string {
if (rows.length === 0) return "no data";
const lines = [this.header(), this.format(rows), "rows: " + rows.length];
return lines.filter((line) => line !== "").join("\n");
}
protected abstract format(rows: Row[]): string; // required step
protected header(): string { return ""; } // hook: optional step
}
class CsvExporter extends Exporter {
protected header() { return "name,score"; }
protected format(rows: Row[]) {
return rows.map((r) => r.name + "," + r.score).join("\n");
}
}
class JsonExporter extends Exporter {
protected format(rows: Row[]) {
return JSON.stringify(rows);
}
}
const rows = [{ name: "Ana", score: 9 }, { name: "Ben", score: 7 }];
console.log(new CsvExporter().export(rows));
// name,score
// Ana,9
// Ben,7
// rows: 2
console.log(new JsonExporter().export(rows));
// [{"name":"Ana","score":9},{"name":"Ben","score":7}]
// rows: 2
console.log(new JsonExporter().export([])); // no dataPemeriksaan data kosong dan footer berada di satu tempat. Exporter XML baru cukup mengimplementasikan format dan mendapatkan sisanya secara gratis.
Gagasan yang sama dengan komposisi
Pewarisan bukan satu-satunya cara. Anda dapat mengoper langkah yang bervariasi sebagai fungsi, yang membuat pola ini menjadi kerabat dekat Strategy dan menghindari hierarki class:
type Row = { name: string; score: number };
type Steps = { format: (rows: Row[]) => string; header?: () => string };
function exportRows(rows: Row[], steps: Steps): string {
if (rows.length === 0) return "no data";
const lines = [steps.header?.() ?? "", steps.format(rows), "rows: " + rows.length];
return lines.filter((line) => line !== "").join("\n");
}
console.log(exportRows([{ name: "Ana", score: 9 }], { format: (r) => r[0].name }));
// Ana
// rows: 1Pilih bentuk ini bila langkahnya kecil dan Anda tidak butuh state bersama di base class, atau bila satu exporter harus menggabungkan langkah dari beberapa sumber.
Kapan dipakai dan kapan tidak
- Pakai bila beberapa class menjalankan algoritma yang sama dengan hanya sedikit langkah yang berbeda, dan Anda ingin menghilangkan bagian yang terduplikasi.
- Pakai di framework yang harus mengendalikan urutan operasi sambil membiarkan pengguna menyesuaikan langkah, seperti setup dan teardown pada test.
- Pakai hook untuk menawarkan titik perluasan opsional tanpa memaksa setiap subclass mengimplementasikannya.
- Jangan dipakai bila variasinya besar atau perlu berubah saat runtime. Strategy, dengan komposisi, lebih fleksibel.
- Hindari hierarki template method yang dalam. Bila subclass meng-override langkah milik subclass dari subclass, alurnya menjadi sulit diikuti.
Penggunaan di dunia nyata
AbstractListdi Java: Anda mengimplementasikanget(int)dansize(), dan base class menyediakan iterasi,indexOf,contains, dan method lain yang dibangun di atasnya.InputStreamdi Java: subclass mengimplementasikanread()satu byte, dan base class mengimplementasikanread(byte[], int, int)dengan memanggilnya (subclass boleh meng-override-nya demi kecepatan).- Framework test: JUnit,
unittestPython, dan lainnya memanggilsetUp, method test, dantearDowndalam urutan tetap, dan Anda meng-override langkah yang dibutuhkan. - Framework UI dengan method life cycle, seperti
componentDidMountpada class component React, memanggil method Anda di titik tetap dalam algoritmanya sendiri.
Pola terkait
| Pola | Perbedaannya dengan Template Method |
|---|---|
| Strategy | Strategy mengganti seluruh algoritma lewat komposisi saat runtime; Template Method menetapkan algoritma dan memvariasikan sebagiannya lewat pewarisan saat compile time. |
| Factory Method | Factory method sering menjadi salah satu langkah dari template method: langkah yang membuat objek. |
| Fungsi hook dan callback | Mengoper callback ke algoritma yang tetap adalah versi berbasis komposisi dari gagasan yang sama. |
FAQ
Apa itu hook dalam pola Template Method?
Hook adalah langkah yang punya implementasi default di base class, sering tidak melakukan apa pun. Subclass boleh meng-override-nya untuk menambah perilaku di titik itu, tetapi tidak wajib.
Apa perbedaan antara Template Method dan Strategy?
Template Method memakai pewarisan: base class memiliki algoritma dan subclass meng-override langkah. Strategy memakai komposisi: context mendelegasikan seluruh algoritma ke objek atau fungsi yang dapat ditukar saat runtime.
Haruskah template method itu sendiri bisa di-override?
Tidak. Tujuannya adalah menetapkan urutan langkah. Di Java atau C# Anda bisa menandainya final atau non-virtual; di TypeScript Anda harus mendokumentasikannya, karena tidak ada kata kunci final.
Apa hubungan Template Method dengan Factory Method?
Factory Method sering merupakan spesialisasi Template Method: algoritma base class menyertakan langkah yang membuat objek, dan subclass menentukan class mana yang dibuat.