Pola desain hanya untuk arsitek Java - setidaknya itulah yang selalu Anda pikirkan. Faktanya, pola desain bermanfaat bagi semua orang. Jika alat-alat ini bukan milik “astronot arsitektur”, lalu alat apakah itu? Mengapa mereka berguna dalam aplikasi PHP? Artikel ini menjelaskan masalah ini.
Buku Design Patterns memperkenalkan pola desain kepada komunitas perangkat lunak. Penulis buku tersebut adalah Erich Gamma, Richard Helm, Ralph Johnson, dan John Vlissides Design (umumnya dikenal sebagai "Gang of Four"). Konsep inti di balik pola desain yang disajikan sangat sederhana. Setelah bertahun-tahun mempraktikkan pengembangan perangkat lunak, Gamma dan yang lainnya telah menemukan pola-pola tertentu dengan desain yang tetap, seperti arsitek mendesain rumah dan bangunan, mengembangkan templat untuk menentukan lokasi kamar mandi atau bagaimana dapur harus dibangun. Menggunakan templat atau pola desain ini berarti merancang bangunan yang lebih baik dengan lebih cepat. Konsep yang sama berlaku untuk perangkat lunak.
Pola desain tidak hanya mewakili cara yang berguna untuk mengembangkan perangkat lunak yang kuat dengan lebih cepat, namun juga menyediakan cara untuk merangkum ide-ide besar dalam istilah yang mudah dipahami. Misalnya, Anda dapat mengatakan bahwa Anda sedang menulis sistem pesan yang menyediakan kopling longgar, atau Anda dapat mengatakan bahwa Anda sedang menulis sebuah pola bernama Observer.
Mendemonstrasikan nilai pola dengan contoh yang lebih kecil sangatlah sulit. Hal ini sering kali terasa berlebihan, karena pola sebenarnya berfungsi dalam basis kode yang besar. Artikel ini tidak mendemonstrasikan aplikasi besar, jadi Anda perlu memikirkan cara menerapkan prinsip-prinsip contoh dalam aplikasi besar Anda—bukan kode itu sendiri yang ditunjukkan dalam artikel ini. Ini bukan berarti Anda tidak boleh menggunakan pola dalam aplikasi kecil. Banyak aplikasi bagus yang dimulai dari aplikasi kecil dan berlanjut ke aplikasi besar, jadi tidak ada alasan untuk tidak mengembangkan praktik pengkodean yang solid seperti ini. Sekarang setelah Anda memahami pola desain dan mengapa pola tersebut berguna, mari kita lihat lima pola yang umum digunakan di PHP V5.
Pola pabrik
Awalnya dalam buku Design Patterns, banyak pola desain yang mendorong penggunaan kopling longgar. Untuk memahami konsep ini, yang terbaik adalah membicarakan perjalanan sulit yang dilalui banyak pengembang dalam mengerjakan sistem besar. Ketika Anda mengubah satu bagian kode, masalah dapat terjadi, dan kerusakan berjenjang dapat terjadi di bagian lain dari sistem—bagian yang sebelumnya Anda anggap tidak berhubungan sama sekali.
Masalahnya adalah kopling yang ketat. Fungsi dan kelas di satu bagian sistem sangat bergantung pada perilaku dan struktur fungsi dan kelas di bagian lain sistem. Anda menginginkan sekumpulan pola yang memungkinkan kelas-kelas ini berkomunikasi satu sama lain, namun Anda tidak ingin mengikatnya secara erat untuk menghindari saling terkait. Dalam sistem besar, banyak kode bergantung pada beberapa kelas kunci. Kesulitan mungkin timbul ketika kelas-kelas ini perlu diubah. Misalnya, Anda memiliki kelas Pengguna yang membaca dari sebuah file. Anda ingin mengubahnya ke kelas lain yang membaca dari database, namun semua kode Anda merujuk pada kelas asli yang membaca dari file. Saat ini, akan sangat nyaman menggunakan mode pabrik.
Pola pabrik adalah kelas yang memiliki metode tertentu yang membuat objek untuk Anda. Anda dapat menggunakan kelas pabrik untuk membuat objek tanpa menggunakan new secara langsung. Dengan cara ini, jika Anda ingin mengubah jenis objek yang dibuat, Anda hanya perlu mengubah pabriknya. Semua kode yang menggunakan pabrik ini diubah secara otomatis.
Listing 1 menunjukkan contoh kelas pabrik. Sisi server dari persamaan ini terdiri dari dua bagian: database dan sekumpulan halaman PHP yang memungkinkan Anda menambahkan umpan balik, meminta daftar umpan balik, dan mendapatkan artikel yang terkait dengan umpan balik tertentu.
Daftar 1. Pabrik1.php
<?php antarmuka IUser { fungsi getName(); }
kelas Pengguna mengimplementasikan IUser { fungsi publik __konstruksi( $id ) {}
fungsi publik getName() { kembalikan "Jack"; } }
kelas UserFactory { fungsi statis publik Buat( $id ) { kembalikan Pengguna baru( $id ); } }
$uo = Pabrik Pengguna::Buat( 1 ); echo( $uo->getName()."n" ); ?> |
Antarmuka IUser mendefinisikan tindakan apa yang harus dilakukan oleh objek pengguna. Implementasi IUser disebut User, dan kelas pabrik UserFactory membuat objek IUser. Hubungan ini dapat diwakili oleh UML pada Gambar 1.
Gambar 1. Kelas pabrik dan antarmuka IUser serta kelas pengguna terkait |
Jika Anda menjalankan kode ini pada baris perintah menggunakan juru bahasa php, Anda akan mendapatkan hasil berikut:
%phpfactory1.php Mendongkrak % |
Kode pengujian akan meminta objek Pengguna dari pabrik dan menampilkan hasil metode getName.
Terdapat varian pola pabrik yang menggunakan metode pabrik. Metode statis publik di kelas ini membuat objek dengan tipe tersebut. Metode ini berguna jika penting untuk membuat objek jenis ini. Misalnya, Anda perlu membuat objek dan kemudian mengatur sejumlah properti. Versi pola pabrik ini merangkum proses dalam satu lokasi, sehingga Anda tidak perlu menyalin kode inisialisasi yang rumit dan menempelkannya ke seluruh basis kode. Listing 2 menunjukkan contoh penggunaan metode pabrik.
Daftar 2. Pabrik2.php
<?php antarmuka IUser { fungsi getName(); }
kelas Pengguna mengimplementasikan IUser { fungsi statis publik Memuat( $id ) { kembalikan Pengguna baru( $id ); }
fungsi statis publik Buat() { kembalikan Pengguna baru( null ); }
fungsi publik __konstruksi( $id ) {}
fungsi publik getName() { kembalikan "Jack"; } }
$uo = Pengguna::Muat( 1 ); echo( $uo->getName()."n" ); ?> |
Kode ini jauh lebih sederhana. Ia hanya memiliki satu antarmuka IUser dan kelas Pengguna yang mengimplementasikan antarmuka ini. Kelas Pengguna memiliki dua metode statis untuk membuat objek. Hubungan ini dapat diwakili oleh UML pada Gambar 2.
Gambar 2. Antarmuka IUser dan kelas pengguna dengan metode pabrik |
Menjalankan skrip pada baris perintah menghasilkan hasil yang sama seperti Listing 1, sebagai berikut:
%phpfactory2.php Mendongkrak % |
Seperti disebutkan di atas, terkadang mode seperti itu tampak berlebihan di lingkungan yang lebih kecil. Namun, yang terbaik adalah mempelajari bentuk pengkodean yang solid yang dapat Anda terapkan pada proyek dengan ukuran berapa pun.
Mode elemen tunggal
Beberapa sumber daya aplikasi bersifat eksklusif karena hanya ada satu sumber daya jenis ini. Misalnya, koneksi ke database melalui pegangan database bersifat eksklusif. Anda ingin berbagi pegangan database di seluruh aplikasi Anda karena ini merupakan overhead ketika menjaga koneksi tetap terbuka atau tertutup, terlebih lagi selama proses pengambilan satu halaman.
Mode elemen tunggal memenuhi persyaratan ini. Jika aplikasi berisi satu dan hanya satu objek pada satu waktu, maka objek tersebut adalah objek tunggal. Kode pada Listing 3 menunjukkan elemen tunggal koneksi database di PHP V5.
Daftar 3. Singleton.php
<?php require_once("DB.php");
kelas Koneksi Basis Data { fungsi statis publik get() { statis $db = nol; jika ( $db == nol ) $db = Koneksi Database baru(); kembalikan $db; }
pribadi $_handle = null; fungsi pribadi __construct() { $dsn = 'mysql://root:password@localhost/foto'; $ini->_handle =& DB::Hubungkan( $dsn, array() ); }
pegangan fungsi publik() { kembalikan $ini->_handle; } }
print("Pegangan = ".DatabaseConnection::get()->pegangan()."n" ); print("Pegangan = ".DatabaseConnection::get()->pegangan()."n" ); ?> |
Kode ini menunjukkan satu kelas bernama DatabaseConnection. Anda tidak dapat membuat DatabaseConnection Anda sendiri karena konstruktornya bersifat pribadi. Namun dengan menggunakan metode get statis, Anda bisa mendapatkan dan hanya mendapatkan satu objek DatabaseConnection. UML untuk kode ini ditunjukkan pada Gambar 3.
Gambar 3. Koneksi database elemen tunggal |
Bukti terbaiknya adalah bahwa pegangan database yang dikembalikan oleh metode pegangan adalah sama di antara kedua panggilan tersebut. Anda dapat menjalankan kode di baris perintah untuk mengamati hal ini.
%php tunggal.php Pegangan = ID objek #3 Pegangan = ID objek #3 % |
Kedua pegangan yang dikembalikan adalah objek yang sama. Jika Anda menggunakan elemen tunggal koneksi database di seluruh aplikasi, Anda dapat menggunakan kembali pegangan yang sama di mana saja.
Anda dapat menggunakan variabel global untuk menyimpan pegangan database, namun pendekatan ini hanya cocok untuk aplikasi yang lebih kecil. Dalam aplikasi yang lebih besar, hindari penggunaan variabel global dan gunakan objek dan metode untuk mengakses sumber daya. Pola pengamat
Pola Pengamat memberi Anda cara lain untuk menghindari sambungan erat antar komponen. Polanya sangat sederhana: suatu objek membuat dirinya dapat diamati dengan menambahkan metode yang memungkinkan objek lain, pengamat, untuk mendaftarkan dirinya. Ketika objek yang dapat diamati berubah, ia mengirimkan pesan ke pengamat yang terdaftar. Pengamat ini menggunakan informasi ini untuk melakukan operasi yang tidak tergantung pada objek yang diamati. Hasilnya adalah objek dapat berbicara satu sama lain tanpa harus memahami alasannya. Contoh sederhananya adalah daftar pengguna dalam sistem. Kode di Listing 4 menampilkan daftar pengguna, dan ketika pengguna ditambahkan, ia mengirimkan pesan. Daftar ini dapat diamati melalui pengamat log yang mengirimkan pesan ketika pengguna ditambahkan.
Daftar 4. Observer.php
<?php antarmuka IObserver { fungsi onChanged( $pengirim, $args ); }
antarmuka IObservable { fungsi addObserver( $pengamat ); }
kelas UserList mengimplementasikan IObservable { pribadi $_observer = array();
fungsi publik addCustomer( $nama ) { foreach( $ini->_observer sebagai $obs ) $obs->onChanged( $ini, $nama ); }
fungsi publik addObserver( $observer ) { $ini->_pengamat []= $pengamat; } }
kelas UserListLogger mengimplementasikan IObserver { fungsi publik onChanged( $sender, $args ) { echo( "'$args' ditambahkan ke daftar penggunan" ); } }
$ul = Daftar Pengguna baru(); $ul->addObserver( UserListLogger baru() ); $ul->addCustomer( "Jack" ); ?> |
Kode ini mendefinisikan empat elemen: dua antarmuka dan dua kelas. Antarmuka IObservable mendefinisikan objek yang dapat diamati, dan UserList mengimplementasikan antarmuka ini untuk mendaftarkan dirinya sebagai objek yang dapat diamati. Daftar IObserver mendefinisikan cara menjadi pengamat. UserListLogger mengimplementasikan antarmuka IObserver. Elemen-elemen ini ditunjukkan dalam UML pada Gambar 4.
Gambar 4. Daftar pengguna yang dapat diamati dan event logger daftar pengguna |
Jika Anda menjalankannya dari baris perintah, Anda akan melihat output berikut:
% php pengamat.php 'Jack' ditambahkan ke daftar pengguna % |
Kode pengujian membuat UserList dan menambahkan pengamat UserListLogger ke dalamnya. Kemudian tambahkan konsumen dan beri tahu UserListLogger tentang perubahan ini.
Penting untuk disadari bahwa UserList tidak mengetahui apa yang akan dilakukan logger. Mungkin ada satu atau lebih pendengar yang melakukan operasi lain. Misalnya, Anda mungkin memiliki pengamat yang mengirimkan pesan ke pengguna baru, menyambut mereka di sistem. Nilai dari pendekatan ini adalah UserList mengabaikan semua objek yang bergantung padanya dan berfokus terutama pada pemeliharaan daftar pengguna dan pengiriman pesan ketika daftar berubah.
Pola ini tidak terbatas pada objek di memori. Ini adalah dasar untuk sistem kueri pesan berbasis database yang digunakan dalam aplikasi yang lebih besar. rantai mode komando
Pola rantai komando didasarkan pada topik yang digabungkan secara longgar, pengiriman pesan, perintah, permintaan, atau apa pun melalui serangkaian penangan. Setiap penangan membuat penilaiannya sendiri mengenai apakah ia dapat menangani permintaan tersebut. Jika bisa, permintaan diproses dan proses dihentikan. Anda dapat menambah atau menghapus penangan dari sistem tanpa mempengaruhi penangan lainnya. Listing 5 menunjukkan contoh pola ini.
Daftar 5. Chain.php
<?php antarmukaICommand { fungsi onCommand( $nama, $args ); }
kelas Rantai Perintah { pribadi $_commands = array();
fungsi publik addCommand( $cmd ) { $ini->_perintah []= $cmd; }
fungsi publik runCommand( $nama, $args ) { foreach( $ini->_perintah sebagai $cmd ) { jika ( $cmd->onCommand( $nama, $args ) ) kembali; } } }
kelas UserCommand mengimplementasikan ICommand { fungsi publik onCommand( $nama, $args ) { if ( $name != 'addUser' ) menghasilkan false; echo("UserCommand menangani 'addUser'n" ); kembali benar; } }
kelas MailCommand mengimplementasikan ICommand { fungsi publik onCommand( $nama, $args ) { if ( $name != 'mail' ) menghasilkan false; echo("Perintah Surat menangani 'surat'n" ); kembali benar; } }
$cc = Rantai Perintah baru(); $cc->addCommand( UserCommand baru() ); $cc->addCommand( new MailCommand() ); $cc->runCommand( 'addUser', null ); $cc->runCommand( 'mail', null ); ?> |
Kode ini mendefinisikan kelas CommandChain yang mengelola daftar objek ICommand. Kedua kelas dapat mengimplementasikan antarmuka ICommand - yang satu merespons permintaan email, dan yang lainnya merespons penambahan pengguna. Gambar 5 menunjukkan UML.
Gambar 5. Rantai perintah dan perintah terkaitnya |
Jika Anda menjalankan skrip yang berisi beberapa kode pengujian, Anda mendapatkan output berikut:
% php rantai.php Perintah Pengguna menangani 'addUser' MailCommand menangani 'mail' % |
Kode pertama-tama membuat objek CommandChain dan menambahkan dua contoh objek perintah ke dalamnya. Kemudian jalankan dua perintah untuk melihat siapa yang merespons perintah tersebut. Jika nama perintah cocok dengan UserCommand atau MailCommand, kode akan gagal dan tidak ada tindakan yang terjadi. Pola rantai perintah sangat berharga saat membuat arsitektur terukur untuk menangani permintaan, dan banyak masalah dapat diselesaikan dengan menggunakannya. pola strategi
Pola desain terakhir yang kita bahas adalah Pola Strategi. Dalam pola ini, algoritma diekstraksi dari kelas yang kompleks dan oleh karena itu dapat dengan mudah diganti. Misalnya, jika Anda ingin mengubah peringkat halaman di mesin pencari, mode Strategi adalah pilihan yang baik. Pikirkan tentang bagian-bagian mesin pencari—mesin yang melintasi halaman, mesin yang memberi peringkat pada setiap halaman, dan mesin pencari lainnya yang mengurutkan hasil berdasarkan peringkat. Dalam contoh kompleks, semua bagian ini berada di kelas yang sama. Dengan menggunakan pola Strategi, Anda dapat memasukkan bagian pengaturan ke kelas lain untuk mengubah cara halaman disusun tanpa mempengaruhi kode mesin pencari lainnya.
Sebagai contoh sederhana, Listing 6 memperlihatkan kelas daftar pengguna yang menyediakan cara untuk menemukan sekumpulan pengguna berdasarkan serangkaian kebijakan plug-and-play.
Daftar 6. Strategi.php
<?php antarmuka IStrategi { filter fungsi( $catatan ); }
kelas FindAfterStrategy mengimplementasikan IStrategy { pribadi $_nama;
fungsi publik __konstruksi( $nama ) { $ini->_nama = $nama; }
filter fungsi publik($record) { kembalikan strcmp( $ini->_nama, $catatan ) <= 0; } }
kelas RandomStrategy mengimplementasikan IStrategy { filter fungsi publik($record) { kembalikan rand( 0, 1 ) >= 0,5; } }
Daftar Pengguna kelas { pribadi $_list = array();
fungsi publik __konstruksi( $nama ) { jika ( $nama != null ) { foreach( $nama sebagai $nama ) { $ini->_daftar []= $nama; } } }
fungsi publik tambahkan( $nama ) { $ini->_daftar []= $nama; }
fungsi publik temukan( $filter ) { $recs = array(); foreach( $ini->_daftar sebagai $pengguna ) { jika ( $filter->filter( $pengguna ) ) $recs []= $pengguna; } kembalikan $recs; } }
$ul = Daftar Pengguna baru( array( "Andy", "Jack", "Lori", "Megan" ) ); $f1 = $ul->find( new FindAfterStrategy( "J" ) ); cetak_r( $f1 );
$f2 = $ul->temukan( RandomStrategy baru() ); cetak_r( $f2 ); ?> |
Gambar 6. Daftar pengguna dan kebijakan yang digunakan untuk memilih pengguna |
Kelas UserList adalah pembungkus array nama. Ini mengimplementasikan metode find, yang menggunakan salah satu dari beberapa strategi untuk memilih subset dari nama-nama ini. Strategi ini ditentukan oleh antarmuka IStrategy, yang memiliki dua implementasi: satu yang memilih pengguna secara acak, dan satu lagi yang memilih semua nama setelah nama yang ditentukan. Saat Anda menjalankan kode pengujian, Anda mendapatkan output berikut:
%php strategi.php Himpunan ( [0] => Mendongkrak [1] =>Lori [2] =>Megan ) Himpunan ( [0] => Andi [1] =>Megan ) % |
Kode pengujian menjalankan daftar pengguna yang sama untuk kedua strategi dan menampilkan hasilnya. Dalam kasus pertama, strateginya mencari nama apa pun yang mengikuti J, sehingga Anda akan mendapatkan Jack, Lori, dan Megan. Strategi kedua memilih nama secara acak, menghasilkan hasil yang berbeda setiap saat. Dalam hal ini, hasilnya adalah Andy dan Megan.
Pola Strategi ideal untuk sistem manajemen data kompleks atau sistem pemrosesan data yang memerlukan fleksibilitas tingkat tinggi dalam cara data disaring, dicari, atau diproses.
Kesimpulan
Artikel ini memperkenalkan beberapa pola desain yang paling umum digunakan dalam aplikasi PHP. Pola desain lebih lanjut ditunjukkan dalam buku Design Patterns. Jangan biarkan mistik arsitektur menghalangi Anda. Pola adalah ide bagus yang dapat digunakan dalam bahasa pemrograman apa pun dan pada tingkat keahlian apa pun.