"Pengantar Menuju Design Pattern & Clean Code"
Object-Oriented Programming (OOP) PHP
Pertemuan 13
Pernahkah Anda membuat aplikasi yang awalnya berjalan lancar, namun saat klien meminta "tambah 1 fitur kecil", tiba-tiba fitur lain ikut error atau buggy?
Untuk mengatasi ini, kita menggunakan 5 pedoman desain OOP yang disebut SOLID.
"Sebuah Class hanya boleh memiliki satu dan HANYA SATU alasan untuk berubah."
Intinya: Satu Class, Satu Tugas Spesifik. Jangan membuat Class dewa (God Class) yang bisa melakukan segalanya.
// ❌ BURUK: Class User melakukan terlalu banyak hal class User { public function simpanKeDatabase() { ... } public function kirimEmailWelcome() { ... } public function cetakLaporanPDF() { ... } }
// ✅ BAIK: Dipecah sesuai tanggung jawabnya class UserRepository { /* urusan database */ } class UserMailer { /* urusan kirim email */ } class UserReport { /* urusan cetak PDF */ }
"Entitas perangkat lunak harus TERBUKA untuk diperluas (ditambah fitur baru), namun TERTUTUP untuk dimodifikasi (mengubah kode lama)."
Gunakan konsep Interface atau Abstract Class agar saat ada tipe baru, kita tidak perlu membongkar IF-ELSE di dalam class utama.
// ❌ BURUK: Kalau mau tambah metode GoPay, harus bongkar class ini! class Pembayaran { public function proses($tipe) { if ($tipe == "Transfer") { ... } elseif ($tipe == "KartuKredit") { ... } } }
// ✅ BAIK: Cukup buat class baru yang implement Interface, // Class utama tidak perlu dimodifikasi sama sekali! interface MetodeBayar { public function bayar(); } class Transfer implements MetodeBayar { ... } class KartuKredit implements MetodeBayar { ... } class GoPay implements MetodeBayar { ... } // Fitur baru ditambahkan dengan aman
Burung punya fungsi terbang(). Lalu kita membuat class anak Penguin extends Burung. Penguin tidak bisa terbang! Ini akan memicu error. Solusinya, pisahkan menjadi BurungTerbang dan BurungBerenang.
Pekerja punya metode bekerja() dan makan(). Jika kita membuat class Robot implements Pekerja, robot dipaksa punya fungsi makan() yang kosong/error. Solusinya, pecah menjadi interface BisaBekerja dan BisaMakan.
"Modul tingkat tinggi (High-level) tidak boleh bergantung langsung pada modul tingkat rendah (Low-level). Keduanya harus bergantung pada abstraksi (Interface/Abstract Class)."
// ❌ BURUK: Aplikasi (High-level) sangat bergantung pada MySQL (Low-level). // Jika kita ingin pindah ke database MongoDB, seluruh kode aplikasi rusak. class TokoOnline { private $db; public function __construct(MySQLConnection $db) { $this->db = $db; } }
// ✅ BAIK: Bergantung pada Interface. // Kita bisa melempar class koneksi apapun asalkan ia mematuhi Interface tersebut. interface DatabaseInterface { public function connect(); } class TokoOnline { private $db; public function __construct(DatabaseInterface $db) { $this->db = $db; } }
Skenario: Bos meminta Anda menambahkan metode pembayaran baru (M-Banking). Mari lihat apa yang terjadi jika sistem Anda dirancang secara buruk (Bad) vs secara baik (SOLID).
// Skenario Tanpa OCP (Kaku) class Checkout { public function bayar($metode) { if ($metode == 'transfer') { /* ... */ } elseif ($metode == 'mbanking') { /* modifikasi file inti! */ } } } // Skenario Dengan OCP (SOLID) interface MetodeBayar { public function proses(); } class MBanking implements MetodeBayar { public function proses() { /* aman ditambah tanpa merusak sistem lama */ } }
SOLID bukanlah aturan yang akan membuat aplikasi Anda berjalan lebih cepat, melainkan aturan yang membuat Anda sebagai Programmer bertahan hidup lebih lama tanpa pusing memelihara kode.
Setelah menguasai SOLID, Anda sudah siap mempelajari Design Pattern (Pola Desain Teruji) seperti Factory Pattern, Singleton, Observer, dan banyak lagi yang digunakan di Framework modern (seperti Laravel, CodeIgniter, dll).