cv.cm

Pemrograman · Pola desain

Pola Prototype dijelaskan dengan contoh

4 menit baca

Jawaban singkat

Prototype adalah pola desain creational yang membuat objek baru dengan menyalin instance yang sudah ada, yaitu prototipe, alih-alih membangunnya dari nol dengan new. Setiap prototipe mengimplementasikan method clone(), sehingga kode klien dapat menduplikasi objek tanpa mengetahui kelas konkretnya. Pola ini berguna ketika objek mahal untuk dikonfigurasi atau hadir dalam banyak variasi preset. Jebakan utamanya adalah shallow copy: objek bersarang harus ikut disalin, atau klon dan aslinya akan berbagi objek tersebut.

Tujuan

Menentukan jenis objek yang dibuat dengan instance prototipikal, dan membuat objek baru dengan menyalin prototipe ini. Pola Prototype adalah salah satu dari lima pola creational dalam buku Gang of Four (GoF).

Masalah yang diselesaikan

Bayangkan editor diagram dengan palet bentuk preset: kotak peringatan merah, catatan biru, lencana "selesai" hijau. Setiap preset punya ukuran, warna, font, dan daftar aturan gaya. Ketika pengguna menyeret preset ke kanvas, editor membutuhkan bentuk baru yang independen dan dimulai tepat dengan pengaturan itu.

Tanpa pola ini, editor membutuhkan fungsi pembuat terpisah untuk setiap preset, dan harus mengenal setiap kelas bentuk konkret. Lebih buruk lagi, preset yang didefinisikan pengguna saat runtime tidak dapat dibuat sama sekali, karena tidak ada kode yang mengetahui pengaturannya sebelumnya. Dengan pola Prototype, editor cukup memanggil preset.clone().

Struktur dan peserta

PesertaTanggung jawabDalam contoh
PrototypeMendeklarasikan interface untuk mengkloning dirinya sendiri.Shape dengan clone()
ConcretePrototypeMengimplementasikan clone() dengan menyalin state miliknya sendiri.Box
KlienMembuat objek baru dengan meminta prototipe mengkloning dirinya.kode editor
Prototype registry (opsional)Menyimpan prototipe bernama agar klien dapat mencarinya.map palette

Implementasi TypeScript

clone() menyalin setiap field, termasuk objek dan array bersarang, sehingga salinan independen dari aslinya:

interface Shape {
  clone(): Shape;
  describe(): string;
}

class Box implements Shape {
  constructor(
    public width: number,
    public height: number,
    public style: { fill: string; border: string },
    public tags: string[],
  ) {}

  clone(): Box {
    // copy nested objects too, so the clone shares nothing mutable
    return new Box(this.width, this.height, { ...this.style }, [...this.tags]);
  }

  describe(): string {
    return `${this.width}x${this.height} ${this.style.fill} [${this.tags.join(", ")}]`;
  }
}

// A registry of named prototypes, which could also be filled at run time.
const palette = new Map<string, Shape>([
  ["warning", new Box(120, 40, { fill: "red", border: "black" }, ["alert"])],
  ["note", new Box(160, 80, { fill: "blue", border: "none" }, [])],
]);

const a = palette.get("warning")!.clone() as Box;
a.width = 200;
a.tags.push("urgent");
console.log(a.describe());                        // 200x40 red [alert, urgent]
console.log(palette.get("warning")!.describe());  // 120x40 red [alert]

Editor tidak pernah menyebut Box. Preset baru adalah entri baru di registry, bukan kelas baru atau fungsi pembuat baru.

Shallow copy versus deep copy

Bug paling umum pada pola Prototype adalah klon yang berbagi objek bersarang dengan aslinya. Salinan dengan spread bersifat shallow: hanya menyalin tingkat teratas.

const original = { name: "note", style: { fill: "blue" } };

const shallow = { ...original };
shallow.style.fill = "green";
console.log(original.style.fill); // green (shared object was changed)

const deep = structuredClone(original);
deep.style.fill = "yellow";
console.log(original.style.fill); // green (unchanged)

structuredClone() sudah tersedia di browser modern dan Node.js serta menyalin data biasa secara deep, termasuk objek bersarang, array, Map, Set, dan Date. Fungsi ini punya dua batasan yang penting di sini:

  • Instance kelas kembali sebagai objek biasa: salinan kehilangan prototype-nya, sehingga method seperti describe() hilang.
  • Fungsi dan node DOM tidak dapat dikloning; structuredClone() melempar DataCloneError.

Kapan memakainya, dan kapan tidak

Gunakan pola Prototype ketika:

  • Objek mahal untuk disiapkan (dimuat dari file, dihitung, dikonfigurasi dalam banyak langkah) dan Anda butuh banyak salinan yang mirip.
  • Kumpulan varian didefinisikan saat runtime, misalnya preset atau templat yang dibuat pengguna.
  • Anda ingin membuat objek tanpa bergantung pada kelas konkretnya, dan tanpa hierarki factory paralel.

Hindari ketika:

  • Objek murah dan sederhana untuk dibuat. Memanggil konstruktor atau fungsi factory lebih jelas.
  • Objek menyimpan sumber daya yang tidak boleh diduplikasi, seperti file terbuka, socket, atau ID unik. Mengkloningnya membutuhkan penanganan khusus.
  • Objek punya referensi melingkar dan kepemilikan yang rumit, sehingga deep copy yang benar sulit dilakukan.

Pemakaian di dunia nyata

  • JavaScript sendiri berbasis prototipe: Object.create(proto) membuat objek baru yang mewarisi dari objek yang sudah ada. Ini terkait tetapi tidak identik dengan pola ini, karena objek baru mendelegasikan ke prototipenya alih-alih menyalinnya.
  • DOM: node.cloneNode(true) menyalin elemen beserta anak-anaknya secara deep, cara umum untuk mencetak fragmen UI yang berulang.
  • Java: kelas dapat mengimplementasikan interface Cloneable dan meng-override Object.clone(), meskipun banyak developer Java lebih suka copy constructor.
  • Game engine dan editor biasanya memunculkan objek baru dari templat yang sudah dikonfigurasi (sering disebut prefab).

Pola terkait

  • Pola Abstract Factory: factory dapat menyimpan sekumpulan prototipe dan membuat produk dengan mengkloningnya, tanpa perlu satu subkelas factory per keluarga.
  • Pola Factory Method: membuat objek lewat subkelas; pola Prototype menghindari subkelas itu dengan menyalin instance.
  • Pola Composite dan pola Decorator: desain yang banyak memakainya sering diuntungkan oleh pola Prototype, karena menyalin struktur yang sudah dikonfigurasi lebih mudah daripada membangunnya ulang.
  • Pola Memento: juga menyalin state objek, tetapi untuk memulihkannya nanti, bukan untuk membuat objek independen baru.

FAQ

Apakah pola Prototype sama dengan prototype JavaScript?

Tidak. Prototype JavaScript adalah mekanisme bahasa untuk inheritance: objek mendelegasikan properti yang tidak ada ke prototipenya. Pola Prototype membuat salinan objek yang independen.

Haruskah clone() membuat deep atau shallow copy?

Biasanya deep untuk data bersarang yang mutable, agar klon dan aslinya tidak saling memengaruhi. Nilai immutable dan sumber daya read-only bersama aman tetap dibagi.

Bisakah saya memakai structuredClone() untuk mengimplementasikan clone()?

Hanya untuk objek data biasa. Untuk instance kelas, structuredClone() mengembalikan objek biasa tanpa method, jadi tulis sendiri logika penyalinannya atau bangun ulang instance dengan konstruktornya.

Kapan pola Prototype lebih baik daripada factory?

Ketika variannya banyak, dikonfigurasi saat runtime, atau mahal untuk disiapkan. Mengkloning instance jadi lebih sederhana daripada menulis fungsi pembuat untuk setiap varian.

Semua tutorial pemrograman