Domain modeling mengajari kita menata kode sesuai masalah bisnis; design pattern mengajari kita menata kode sesuai masalah desain yang muncul berulang. Hampir semua program bertemu masalah sejenis: penciptaan objek yang rumit, antarmuka yang tidak kompatibel, algoritma yang perlu ditukar saat program berjalan. Alih-alih menemukan jalan keluar dari nol setiap kali, komunitas perangkat lunak menabung solusi terbaik, memberi solusi tersebut nama, dan menyusun katalognya. Chapter ini memperkenalkan katalog klasik tersebut, tiga kategorinya, dan satu hal yang sering luput: kita sudah memakai pola tersebut setiap hari lewat pustaka standar Java.
Asal Mula Katalog GoF #
Titik awalnya adalah buku Design Patterns: Elements of Reusable Object-Oriented Software yang diterbitkan tahun 1994 oleh empat penulis — Erich Gamma, Richard Helm, Ralph Johnson, dan John Vlissides — yang kemudian dikenal sebagai Gang of Four (GoF). Buku tersebut memuat 23 pola yang diambil dari desain sistem nyata, masing-masing didokumentasikan dengan format yang seragam: nama pola, masalah yang dijawab, struktur solusi, dan konsekuensi yang menyertainya. Format ini penting karena pola bukan potongan kode siap salin, melainkan pengetahuan berbentuk keputusan desain.
Sebelum GoF, gagasan pattern language dipinjam dari dunia arsitektur bangunan melalui karya Christopher Alexander. Para penulis GoF menerjemahkan ide itu ke perangkat lunak: masalah desain yang berulang layak memiliki jawaban baku yang bisa dirujuk namanya. Sejak 1994, katalog terus bertambah — Repository, Unit of Work, dan Dependency Injection adalah pola yang lahir sesudahnya — sehingga angka 23 hanyalah titik sejarah, bukan batas.
Tiga Kategori Pola #
GoF membagi 23 polanya ke dalam tiga kategori sesuai sifat masalah yang dijawab:
| Kategori | Masalah inti | Contoh pola | Wujud di JDK |
|---|---|---|---|
| Creational | Bagaimana objek diciptakan | Factory Method, Abstract Factory, Builder, Prototype, Singleton | List.of(...) sebagai static factory |
| Structural | Bagaimana objek disusun dan dijembatani | Adapter, Decorator, Facade, Composite, Proxy | BufferedReader sebagai decorator |
| Behavioral | Bagaimana objek berinteraksi dan membagi tanggung jawab | Strategy, Observer, Command, Iterator, Template Method | Comparator sebagai strategy, Iterator pada koleksi |
Pembagian ini membantu kita mencari pola yang tepat: bila persoalannya “kode klien terlalu tahu cara membuat objek”, jawabannya ada di keluarga creational; bila “antarmuka tidak cocok”, kita melirik structural; bila “perilaku perlu berganti saat runtime”, kandidatnya behavioral.
Pola sebagai Kosakata Komunikasi #
Manfaat pola yang paling sering diremehkan bukan kode, melainkan nama. Kalimat “bungkus NotifikasiEmail dengan decorator supaya bisa ditumpuk lapisan sms dan log” memindahkan seluruh struktur desain ke kepala pendengar dalam satu kalimat — tanpa pola, kalimat yang sama perlu mendeskripsikan class pembungkus, pewarisan antarmuka yang sama, dan penerusan method satu per satu. Nama pola bekerja seperti istilah medis bagi dokter: padat, presisi, dan langsung memicu struktur yang sudah dikenal.
Nama juga mengawasi arah diskusi desain. Saat seorang reviewer menulis “kelas ini sebaiknya jadi observer, bukan di-polling tiap detik”, usulan tersebut bisa dibantah atau didukung dengan argumen konsekuensi pola — decoupling yang dihasilkan, urutan notifikasi yang harus dijaga — bukan dengan selera pribadi. Dalam tim, kosakata bersama seperti ini memperpendek rapat dan mengurangi salah paham.
Pola yang Sudah Anda Pakai Setiap Hari #
Pustaka standar Java adalah museum pola yang hidup: kita memakai strategy setiap kali mengurutkan, decorator setiap kali membungkus pembaca berkas, dan static factory setiap kali memanggil List.of. Program berikut membuktikan ketiganya dalam satu berkas singkat:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class PolaDiJdk {
public static void main(String[] args) throws IOException {
List<String> namaProduk = new ArrayList<>(List.of("Tas", "Buku", "Pena", "Penghapus"));
// Strategy (behavioral): algoritma pengurutan dikemas sebagai objek yang bisa dioper
Comparator<String> panjangLaluAbjad = Comparator.comparingInt(String::length)
.thenComparing(Comparator.naturalOrder());
namaProduk.sort(panjangLaluAbjad);
System.out.println("urut panjang lalu abjad: " + namaProduk);
// Decorator (structural): pembungkus menambah perilaku di atas pembaca lain
try (BufferedReader pembaca = new BufferedReader(
new StringReader("baris pertama\nbaris kedua"))) {
System.out.println("dibaca: " + pembaca.readLine());
System.out.println("dibaca: " + pembaca.readLine());
}
}
}Output yang Dihasilkan:
urut panjang lalu abjad: [Tas, Buku, Pena, Penghapus]
dibaca: baris pertama
dibaca: baris keduaMari kita bedah tiga pola yang bersarang di program tersebut:
- Baris 12 (
new ArrayList<>(List.of(...))):List.ofadalah static factory milik JDK — satu nama penciptaan yang jelas untuk koleksi yang tidak dapat diubah. Daftar tersebut dibungkusArrayListkarena pengurutan di tempat (sort) menuntut daftar yang bisa diubah. - Baris 14-16 (
Comparator.comparingInt(...).thenComparing(...)):Comparatoradalah strategy — algoritma pembanding dikemas sebagai objek yang bisa dioper kesort. MethodthenComparingmenyusun strategi kecil menjadi strategi gabungan tanpa membuat class baru. - Baris 17 (
namaProduk.sort(...)): daftar menerima algoritma dari luar; struktur data tetap pasif. Inilah inti strategy: kode yang berubah (aturan urut) dipisahkan dari kode yang tidak (mekanisme urut). - Baris 20-24 (
new BufferedReader(new StringReader(...))):BufferedReaderadalah decorator yang menambah perilaku buffering di atas pembaca apa pun — di siniStringReader. try-with-resources menutup kedua lapisan sekaligus, dan pemanggil tidak perlu tahu lapisan dalamnyaStringReaderatauFileReader.
Lima chapter berikutnya membedah pola-pola tersering satu per satu dengan program yang dapat dijalankan, dimulai dari pola penciptaan yang paling sering dipakai: factory pattern.
Referensi #
- Martin Fowler: Patterns of Enterprise Application Architecture — Catalog
- Oracle: The Java Tutorials (dev.java)
- Oracle: JDK 25 API Specification
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
PolaDiJdk.java
Unduh berkasimport java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class PolaDiJdk {
public static void main(String[] args) throws IOException {
List<String> namaProduk = new ArrayList<>(List.of("Tas", "Buku", "Pena", "Penghapus"));
// Strategy (behavioral): algoritma pengurutan dikemas sebagai objek yang bisa dioper
Comparator<String> panjangLaluAbjad = Comparator.comparingInt(String::length)
.thenComparing(Comparator.naturalOrder());
namaProduk.sort(panjangLaluAbjad);
System.out.println("urut panjang lalu abjad: " + namaProduk);
// Decorator (structural): pembungkus menambah perilaku di atas pembaca lain
try (BufferedReader pembaca = new BufferedReader(
new StringReader("baris pertama\nbaris kedua"))) {
System.out.println("dibaca: " + pembaca.readLine());
System.out.println("dibaca: " + pembaca.readLine());
}
}
}