cv.cm

Pemrograman · Pola desain

Penjelasan pola Template Method beserta contohnya

5 menit baca

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

PeranTanggung jawab
Abstract classMengimplementasikan template method, yang memanggil langkah dalam urutan tetap; mendeklarasikan langkah abstrak dan dapat menyediakan hook
Template methodMethod publik yang mendefinisikan algoritma; biasanya tidak untuk di-override
Primitive operationLangkah abstrak yang harus diimplementasikan setiap subclass
HookLangkah dengan implementasi default (sering kosong) yang boleh di-override subclass
Concrete classMengimplementasikan 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 data

Pemeriksaan 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: 1

Pilih 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

  • AbstractList di Java: Anda mengimplementasikan get(int) dan size(), dan base class menyediakan iterasi, indexOf, contains, dan method lain yang dibangun di atasnya.
  • InputStream di Java: subclass mengimplementasikan read() satu byte, dan base class mengimplementasikan read(byte[], int, int) dengan memanggilnya (subclass boleh meng-override-nya demi kecepatan).
  • Framework test: JUnit, unittest Python, dan lainnya memanggil setUp, method test, dan tearDown dalam urutan tetap, dan Anda meng-override langkah yang dibutuhkan.
  • Framework UI dengan method life cycle, seperti componentDidMount pada class component React, memanggil method Anda di titik tetap dalam algoritmanya sendiri.

Pola terkait

PolaPerbedaannya dengan Template Method
StrategyStrategy mengganti seluruh algoritma lewat komposisi saat runtime; Template Method menetapkan algoritma dan memvariasikan sebagiannya lewat pewarisan saat compile time.
Factory MethodFactory method sering menjadi salah satu langkah dari template method: langkah yang membuat objek.
Fungsi hook dan callbackMengoper 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.

Semua tutorial pemrograman