cv.cm

Pemrograman · Pola desain

Pola Factory Method dijelaskan dengan contoh

4 menit baca

Jawaban singkat

Factory Method adalah pola desain creational yang mendefinisikan sebuah method untuk membuat objek tetapi membiarkan subkelas menentukan kelas konkret mana yang diinstansiasi. Kelas dasar menulis logikanya terhadap interface produk dan memanggil factory method, seperti createTransport(), alih-alih new. Dengan begitu Anda dapat menambah tipe produk baru dengan menambah subkelas, tanpa mengedit kode yang memakai produk tersebut.

Tujuan

Mendefinisikan interface untuk membuat objek, tetapi membiarkan subkelas menentukan kelas mana yang diinstansiasi. Pola Factory Method memungkinkan sebuah kelas menunda instansiasi ke subkelas. Pola ini salah satu dari lima pola creational dalam buku Gang of Four (GoF), dan satu-satunya pola creational yang berlingkup kelas, karena bergantung pada inheritance.

Masalah yang diselesaikan

Bayangkan modul notifikasi. Modul itu memformat pesan, mengirimnya, dan mencatat hasilnya. Awalnya hanya mengirim email, jadi kode memanggil new EmailChannel() secara langsung. Lalu produk butuh SMS, kemudian notifikasi push. Setiap kanal baru berarti mengedit kelas yang sama dan menambah cabang if lagi, padahal langkah pemformatan dan pencatatan tidak pernah berubah.

Alur pengiriman bersifat stabil; hanya jenis kanalnya yang bervariasi. Pola Factory Method memindahkan satu keputusan yang bervariasi, yaitu kelas mana yang dibuat, ke dalam satu method yang dapat di-override.

Struktur dan peserta

PesertaTanggung jawabDalam contoh
ProductInterface dari objek yang dibuat oleh factory method.Channel
ConcreteProductMengimplementasikan interface Product.EmailChannel, SmsChannel
CreatorMendeklarasikan factory method dan berisi logika yang memakai produk.Notifier
ConcreteCreatorMeng-override factory method untuk mengembalikan ConcreteProduct tertentu.EmailNotifier, SmsNotifier

Implementasi TypeScript

interface Channel {
  send(to: string, text: string): string;
}

class EmailChannel implements Channel {
  send(to: string, text: string): string { return `email to ${to}: ${text}`; }
}

class SmsChannel implements Channel {
  send(to: string, text: string): string { return `sms to ${to}: ${text.slice(0, 20)}`; }
}

abstract class Notifier {
  // The factory method: subclasses choose the concrete product.
  protected abstract createChannel(): Channel;
  // Shared logic that works with any Channel.
  notify(to: string, text: string): void {
    const channel = this.createChannel();
    const result = channel.send(to, text.trim());
    console.log("[log]", result);
  }
}

class EmailNotifier extends Notifier {
  protected createChannel(): Channel { return new EmailChannel(); }
}

class SmsNotifier extends Notifier {
  protected createChannel(): Channel { return new SmsChannel(); }
}

const notifiers: Notifier[] = [new EmailNotifier(), new SmsNotifier()];
for (const n of notifiers) n.notify("ada", " Your order has shipped today ");
// [log] email to ada: Your order has shipped today
// [log] sms to ada: Your order has shipp

Menambah notifikasi push sekarang berarti menulis PushChannel dan PushNotifier. Method notify, dan setiap pemanggilnya, tidak berubah.

Sebelum menerapkan pola ini, keputusan pembuatan terkubur dalam logika bersama:

class Notifier {
  constructor(private kind: "email" | "sms") {}
  notify(to: string, text: string): void {
    // every new channel edits this method
    const result = this.kind === "email"
      ? `email to ${to}: ${text}`
      : `sms to ${to}: ${text.slice(0, 20)}`;
    console.log("[log]", result);
  }
}

Alternatif yang lebih ringan: teruskan fungsi factory

Pola Factory Method memakai inheritance. Di TypeScript, Anda sering mendapatkan fleksibilitas yang sama dengan composition, yaitu meneruskan fungsi pembuat ke konstruktor. Cara ini menghindari satu subkelas per produk:

interface Channel { send(to: string, text: string): string; }
class Notifier {
  constructor(private createChannel: () => Channel) {}
  notify(to: string, text: string): void {
    console.log("[log]", this.createChannel().send(to, text));
  }
}
const push = new Notifier(() => ({ send: (to, text) => `push to ${to}: ${text}` }));
push.notify("ada", "Hello"); // [log] push to ada: Hello

Gunakan versi subkelas ketika setiap creator memang sudah punya kelas sendiri karena alasan lain, atau ketika framework mengharapkan Anda memperluas kelas dasar. Gunakan versi fungsi ketika satu-satunya perbedaan antarvarian adalah objek yang mereka buat.

Kapan memakainya, dan kapan tidak

Gunakan pola Factory Method ketika:

  • Sebuah kelas berisi algoritma yang stabil tetapi tidak bisa tahu sebelumnya objek konkret mana yang harus dibuat.
  • Anda menulis framework atau pustaka dan ingin pengguna memasang kelas produk mereka sendiri lewat subclassing.
  • Anda ingin menyimpan logika pembuatan sebuah tipe di satu tempat alih-alih menyebar pemanggilan new.

Hindari ketika:

  • Hanya ada satu tipe produk dan tidak ada tanda nyata akan ada yang kedua. new langsung lebih jelas.
  • Satu-satunya alasan adalah agar pengujian memungkinkan. Meneruskan dependensi lewat konstruktor lebih sederhana.
  • Anda akan membuat hierarki creator paralel yang mencerminkan produk satu lawan satu tanpa logika lain.

Pemakaian di dunia nyata

  • Koleksi Java: Iterable.iterator() dideklarasikan sekali, dan setiap kelas koleksi (ArrayList, HashSet, dan lainnya) meng-override-nya untuk mengembalikan kelas iterator miliknya sendiri. Buku GoF menjelaskan pemakaian pola Factory Method ini untuk iterasi polimorfik.
  • Iterable JavaScript: setiap iterable mengimplementasikan [Symbol.iterator](), method yang mengembalikan iterator baru yang sesuai dengan koleksi tersebut.
  • Framework UI sering membiarkan subkelas meng-override method yang membuat komponen, sel, atau view, sementara kelas dasar mengendalikan tata letak dan siklus hidup.

Pola terkait

PolaPerbedaannya
Abstract FactoryMembuat satu keluarga produk terkait lewat objek dengan beberapa method pembuat. Method-nya sering diimplementasikan sebagai factory method.
Template MethodFactory Method sering dipanggil dari template method, seperti notify memanggil createChannel di atas.
PrototypeMembuat objek dengan menyalin instance alih-alih membuat subkelas creator, sehingga tidak memerlukan hierarki creator paralel.
BuilderBerfokus membangun satu objek kompleks langkah demi langkah, bukan memilih kelas mana yang dibuat.

FAQ

Apa beda pola Factory Method dan pola Abstract Factory?

Factory Method adalah satu method yang di-override subkelas untuk membuat satu produk. Abstract Factory adalah objek dengan beberapa method pembuat yang menghasilkan keluarga produk terkait yang harus dipakai bersama.

Apakah fungsi factory sederhana sama dengan Factory Method?

Tidak persis. Fungsi seperti createShape(kind) dengan switch di dalamnya sering disebut simple factory. Factory Method ala GoF bergantung pada subkelas yang meng-override method pembuat, tetapi keduanya menyembunyikan new dari klien.

Apakah pola Factory Method mengikuti open/closed principle?

Ya. Anda menambah produk baru dengan menambah kelas produk baru dan subkelas creator baru, tanpa mengubah logika creator yang ada.

Haruskah factory method bersifat abstract?

Tidak. Kelas dasar dapat menyediakan implementasi default yang mengembalikan produk standar, dan subkelas meng-override-nya hanya ketika membutuhkan sesuatu yang berbeda.

Semua tutorial pemrograman