cv.cm

Pemrograman · Pola desain

Design pattern dijelaskan: 23 pola Gang of Four

7 menit baca

Jawaban singkat

Design pattern adalah solusi bernama yang dapat dipakai ulang untuk masalah yang terus muncul dalam desain perangkat lunak, dijelaskan pada tingkat di atas kode konkret. Katalog klasiknya adalah buku tahun 1994 Design Patterns: Elements of Reusable Object-Oriented Software karya Gamma, Helm, Johnson, dan Vlissides ("Gang of Four", GoF), yang mendaftar 23 pola dalam tiga kelompok: 5 creational, 7 structural, dan 11 behavioral. Pola memberi tim kosakata bersama, tetapi pola adalah alat untuk masalah tertentu, bukan tujuan itu sendiri.

Apa itu design pattern

Design pattern bukan pustaka atau potongan kode yang tinggal disalin. Design pattern adalah deskripsi masalah yang berulang, inti solusinya, dan trade-off dari pemakaiannya. Anda tetap menulis kodenya sendiri, disesuaikan dengan bahasa dan program Anda.

Buku GoF menjelaskan setiap pola dengan empat elemen penting:

  • Nama: satu atau dua kata yang memungkinkan developer membicarakan desain, misalnya "kita bisa membungkusnya dengan pola Decorator".
  • Masalah: kapan pola diterapkan, dan situasi yang membuatnya diperlukan.
  • Solusi: kelas atau objek yang terlibat, tanggung jawabnya, dan cara mereka berkolaborasi.
  • Konsekuensi: biaya dan manfaatnya, misalnya fleksibilitas lebih besar dengan imbalan lebih banyak kelas.

Gagasan ini berasal dari arsitektur. Buku Christopher Alexander, A Pattern Language (1977), menjelaskan solusi berulang untuk bangunan dan kota, dan para penulis GoF menerapkan gagasan yang sama pada perangkat lunak berorientasi objek.

Buku Gang of Four

Design Patterns: Elements of Reusable Object-Oriented Software diterbitkan Addison-Wesley pada 1994. Contohnya memakai C++ dan Smalltalk, tetapi polanya berlaku untuk bahasa berorientasi objek apa pun, termasuk Java, C#, TypeScript, Python, dan Kotlin.

Selain katalog, buku ini menganjurkan dua prinsip umum yang mendasari sebagian besar pola:

  • Program to an interface, not an implementation. Kode sebaiknya bergantung pada apa yang bisa dilakukan sebuah objek, bukan pada kelas konkretnya.
  • Favor object composition over class inheritance. Membangun perilaku dengan menggabungkan objek biasanya lebih fleksibel daripada membangun hierarki kelas yang dalam.

Buku ini juga mengklasifikasikan setiap pola menurut cakupannya: pola kelas memakai inheritance dan ditetapkan saat kompilasi (pola Factory Method, pola Adapter versi kelas, pola Interpreter, pola Template Method), sedangkan pola objek memakai composition dan dapat berubah saat runtime (semua yang lain).

Semua 23 pola GoF menurut kategori

Pola creational mengatur cara objek dibuat. Pola structural mengatur cara kelas dan objek digabungkan menjadi struktur yang lebih besar. Pola behavioral mengatur cara objek berkomunikasi dan berbagi tanggung jawab.

PolaKategoriTujuan dalam satu kalimat
Abstract FactoryCreationalMembuat keluarga objek yang saling terkait tanpa menyebut kelas konkretnya.
BuilderCreationalMembangun objek kompleks langkah demi langkah, memisahkan konstruksi dari representasinya.
Factory MethodCreationalMembiarkan subkelas menentukan kelas mana yang diinstansiasi.
PrototypeCreationalMembuat objek baru dengan menyalin instance yang sudah ada.
SingletonCreationalMemastikan sebuah kelas hanya punya satu instance dan menyediakan akses global ke instance itu.
AdapterStructuralMengubah satu interface menjadi interface lain yang diharapkan klien.
BridgeStructuralMemisahkan abstraksi dari implementasinya agar keduanya dapat bervariasi secara independen.
CompositeStructuralMemperlakukan objek tunggal dan pohon objek dengan cara yang sama.
DecoratorStructuralMenambahkan tanggung jawab ke objek secara dinamis dengan membungkusnya.
FacadeStructuralMenyediakan satu interface sederhana untuk subsistem yang kompleks.
FlyweightStructuralBerbagi state yang sama agar sejumlah besar objek kecil dapat didukung secara efisien.
ProxyStructuralMenyediakan pengganti yang mengontrol akses ke objek lain.
Chain of ResponsibilityBehavioralMeneruskan permintaan sepanjang rantai handler sampai ada yang menanganinya.
CommandBehavioralMengubah permintaan menjadi objek agar dapat diantrekan, dicatat, atau dibatalkan.
InterpreterBehavioralMerepresentasikan tata bahasa dari bahasa sederhana sebagai kelas dan mengevaluasi kalimat di dalamnya.
IteratorBehavioralMengakses elemen koleksi secara berurutan tanpa membuka struktur internalnya.
MediatorBehavioralMemusatkan komunikasi antarobjek agar mereka tidak saling merujuk secara langsung.
MementoBehavioralMenangkap dan memulihkan state objek tanpa merusak enkapsulasi.
ObserverBehavioralMemberi tahu semua dependen secara otomatis ketika sebuah objek berubah.
StateBehavioralMembiarkan objek mengubah perilakunya ketika state internalnya berubah.
StrategyBehavioralMembuat sekumpulan algoritma dapat dipertukarkan di balik satu interface.
Template MethodBehavioralMendefinisikan kerangka algoritma dan membiarkan subkelas mengisi beberapa langkahnya.
VisitorBehavioralMenambahkan operasi baru pada hierarki kelas tanpa mengubah kelas-kelas tersebut.

Pola dalam praktik: pola Strategy di TypeScript

Berikut contoh kecil sebuah pola yang bekerja. Sebuah checkout harus menghitung ongkos kirim dengan berbagai cara. Alih-alih rantai if/else yang terus memanjang, setiap aturan menjadi objek yang dapat dipertukarkan di balik satu interface:

interface ShippingStrategy {
  cost(weightKg: number): number;
}
class FlatRate implements ShippingStrategy {
  cost(): number { return 5; }
}
class PerKilogram implements ShippingStrategy {
  cost(weightKg: number): number { return 2 * weightKg; }
}
class Checkout {
  constructor(private shipping: ShippingStrategy) {}
  setShipping(s: ShippingStrategy): void { this.shipping = s; }
  total(itemsPrice: number, weightKg: number): number {
    return itemsPrice + this.shipping.cost(weightKg);
  }
}
const checkout = new Checkout(new FlatRate());
console.log(checkout.total(40, 3)); // 45
checkout.setShipping(new PerKilogram());
console.log(checkout.total(40, 3)); // 46

Di TypeScript, fungsi adalah nilai, sehingga desain yang sama dapat ditulis dengan kode lebih sedikit. Ini tema yang umum: banyak pola menjadi lebih sederhana, atau hilang, pada bahasa dengan fungsi first-class.

type Shipping = (weightKg: number) => number;
const flatRate: Shipping = () => 5;
const perKilogram: Shipping = (w) => 2 * w;
function total(itemsPrice: number, weightKg: number, shipping: Shipping): number {
  return itemsPrice + shipping(weightKg);
}
console.log(total(40, 3, flatRate));    // 45
console.log(total(40, 3, perKilogram)); // 46

Cara memilih pola

Mulailah dari masalah, jangan pernah dari polanya. Pola layak menambah kelas hanya jika menghilangkan kesulitan nyata dalam kode Anda. Pertanyaan berikut menunjuk ke kandidat yang biasa:

Jika masalah Anda adalah...Pertimbangkan
Kode tidak boleh bergantung pada kelas konkret yang dibuatnyaPola Factory Method, pola Abstract Factory
Konstruktor memiliki banyak parameter opsionalPola Builder
Anda perlu menyesuaikan kelas yang ada ke interface yang berbedaPola Adapter
Pustaka kompleks membutuhkan satu pintu masuk yang sederhanaPola Facade
Anda ingin menambah fitur ke objek tanpa ledakan jumlah subkelasPola Decorator
Anda bekerja dengan struktur pohon, seperti menu, file, atau widget UIPola Composite, pola Visitor, pola Iterator
Banyak bagian harus bereaksi ketika satu objek berubahPola Observer
Perilaku bergantung pada mode atau status dengan banyak cabangPola State
Anda butuh algoritma atau aturan yang dapat dipertukarkanPola Strategy
Aksi harus bisa dibatalkan, diantrekan, atau dicatatPola Command, pola Memento
  1. Tulis dulu kode paling sederhana yang berfungsi.
  2. Ketika perubahan yang sama terus menyakitkan (misalnya, setiap jenis pembayaran baru mengubah lima file), beri nama masalahnya.
  3. Cari pola yang menangani masalah itu dan baca konsekuensinya.
  4. Terapkan versi terkecil dari pola yang menghilangkan masalah tersebut, lalu berhenti di situ.

Kritik dan batasan

Design pattern berguna, tetapi sering disalahgunakan. Kritik yang umum perlu diketahui:

  • Pemakaian berlebihan: menambah factory, interface, dan manager "untuk jaga-jaga" membuat kode sederhana sulit dibaca. Ini kadang disebut pattern fever.
  • Fitur bahasa yang hilang: pada 1996 Peter Norvig menunjukkan bahwa 16 dari 23 pola GoF tidak terlihat atau lebih sederhana pada bahasa dinamis seperti Lisp dan Dylan. Fungsi first-class menggantikan pola Strategy dan pola Command, dan iterator bawaan menggantikan pola Iterator.
  • Pola Singleton khususnya dianggap luas sebagai anti-pattern jika dipakai sebagai state global, karena menyembunyikan dependensi dan mempersulit pengujian.
  • Katalog ini berasal dari 1994. Praktik selanjutnya menambahkan pola terkenal lain yang tidak ada di buku, seperti dependency injection, repository, dan berbagai varian Model-View-Controller.

Nilai abadi buku ini adalah kosakata dan kebiasaan memikirkan trade-off. Mengatakan "ini pola Adapter" memberi tahu developer lain banyak hal dalam dua kata.

Prinsip terkait

Pola sering dijelaskan bersama prinsip SOLID dalam desain berorientasi objek. Misalnya, pola Strategy dan pola Decorator adalah cara langsung mengikuti open/closed principle, dan pola Abstract Factory adalah cara umum menerapkan dependency inversion principle. Mempelajari prinsipnya membantu Anda memahami mengapa sebuah pola berbentuk seperti itu.

FAQ

Ada berapa design pattern?

Buku Gang of Four mengatalogkan 23 pola: 5 creational, 7 structural, dan 11 behavioral. Banyak pola lain telah dijelaskan sejak itu, misalnya untuk konkurensi, aplikasi enterprise, dan antarmuka pengguna.

Design pattern mana yang sebaiknya dipelajari dulu?

Mulai dari yang paling sering Anda temui di kode nyata: pola Strategy, pola Observer, pola Factory Method, pola Decorator, pola Adapter, dan pola Facade. Setelah itu pelajari pola Builder, pola Composite, dan pola Command.

Apakah design pattern masih relevan?

Ya, sebagai kosakata bersama dan sebagai solusi untuk masalah yang berulang. Beberapa pola kini sudah tertanam di bahasa dan framework, sehingga Anda memakainya tanpa menulis struktur kelas lengkapnya.

Apakah design pattern hanya berlaku untuk bahasa berorientasi objek?

Pola GoF ditulis untuk bahasa berorientasi objek, tetapi gagasan dasarnya muncul di mana-mana. Pada bahasa fungsional, banyak di antaranya menjadi fungsi higher-order yang sederhana.

Apa bedanya design pattern dengan algoritma?

Algoritma adalah urutan langkah yang tepat untuk menyelesaikan masalah komputasi, seperti pengurutan. Design pattern menjelaskan cara mengorganisasi kode dan tanggung jawab, dan disesuaikan untuk setiap program, bukan diikuti langkah demi langkah.

Semua tutorial pemrograman