Bridge Pattern ini merupakan pattern yang kuat (powerfull) dan sering
digunakan dalam pengembangan. Dan ini sebanding dengan usaha untuk mempelajarinya yang cukup menantang.
Untuk memahami design pattern yang satu ini, kita perlu melihat makna decouple (tidak berpasangan), abstraction (abstraksi), dan implementation (implementasi) dari sisi yang berbeda terlebih dahulu.
Decouple adalah
bagaimana objek tidak terhubung satu sama lain, berdiri sendiri (independent), terpisah.
Abstraksi adalah konsep bagaimana antar objek saling terhubung.
Sedangkan “implementasi” janganlah dipandang sebagai penurunan dari suatu kelas abstrak (concrete class). Pandanglah “implementasi” sebagai objek lain yang digunakan oleh kelas abstrak (dan turunannya) untuk mengimplementasi dirinya (“nya” ditujukan untuk kelas abstrak).
Dalam sebagian besar tutorial, bridge pattern didefinisikan sebagai
pattern yang berusaha memisahkan antara abstraksi dan implementasi.
Bingung? Hehe.. Namanya juga teori, biasanya mengawang-awang jika tidak diaplikasikan. Yuk kita aplikasikan!
(Untuk contoh
bridge pattern ini, saya ambil dari buku
Design Patterns JAVA Workbook .)
Misalkan kita punya modal diagram kelas yang pada superclassnya terdapat sebuah kelas abstrak “MachineController”. Nah, di dalam MachineController ini terdapat beberapa
abstract dan
concrete method. Salah satu
concrete method pada MachineController, yaitu
inputfull, menggunakan hasil dari salah satu
abstract method “getQueueMax()”.
public boolean inputfull(){
return getQueueMax() >= getQueue.size();
}
Dan selayaknya sebuah
abstract method, method
getQueueMax() ini baru akan didefinisikan dalam kelas yang turunan MachineController, yaitu StarPressController dan ShellController. Kedua kelas turunan ini mendefinisikan method
getQueueMax() dengan cara yang berbeda. Berikut ini adalah diagram kelas yang dimaksudkan :
Sampai disini, masih baik-baik saja.
Kemudian pada suatu hari, kita baru menyadari bahwa kita membutuhkan mekanisme (
controller) yang berbeda pada untuk proses pengetesan.
Misalkan kita membutuhkan satu tambahan method pada kelas abstrak MachineController, yaitu method
overflow(). Maka kita akan membuat sebuah kelas baru, kelas abstrak TestController, yang diturunkan dari kelas MachineController.
Sebagai kelas abstark, TestController membutuhkan StarPressController dan ShellController untuk mendefinisikan method abstrak getQueueMax(). Maka bentuk diagram kelas yang kita miliki sekarang adalah :
Dengan penambahan suatu mekanisme baru, maka bertambahlah tiga buah kelas pada diagram kelas kita. Bagaimana nanti jika kita akan menambahkan dua mekanisme baru? Berarti akan ada penambahan enam kelas baru! Bagaimana jika ada sepuluh mekanisme baru?! Begitu seterusnya hingga kelas-kelas ini beranak-pinak.
Keruwetan ini dapat ditangani oleh bridge pattern.
Langkah yang perlu dilakukan adalah :
-
Buatlah sebuah interface yang berisi method-method abstrak dari superclass (MachineController).
-
Untuk kelas-kelas yang mendefinisikan method abstrak dengan definisi yang berbeda, pindahkan letakkan dibawah interface. (implements)
-
Kelas abstrak MachineController didefinisikan sebagai concrete class .
-
Lakukan aggregasi! Buatlah sebuah atribut yang merupakan instans dari interface DriverController. Gunakan instans ini untuk mengakses method-method pada interface DriverController sebagai pengisi dari method konkrit, contohnya inputfull(). [Karena inputfull membutuhkan method getQueueMax()] Maka “bentuk” method inputfull() sekarang adalah :
public boolean inputfull(){
return driver.getQueueMax() <= driver.getQueue.getSize();
}
Dan diagram kelas kita sekarang adalah :
Nah, sekarang jika kita menginginkan mekanisme kontrol yang baru, tinggal membuat SEBUAH kelas yang diturunkan dari MachineController, semisal dengan TestController. Demikian pula jika suatu saat nanti kita membutuhkan tipe driver yang baru, maka kita tinggal menambah sebuah kelas yang mengimplementasikan DriverController, semisal dengan ShellDriver.
Inilah bridge pattern yang berhasil memisahkan (decouple) antara abstraksi dengan implementasinya.
Dalam bukunya “Design Pattern Explained : A New Perspective on Object-Oriented Design”, Alan Shalloway dan James R. Trott menyatakan bahwa penurunan memang merupakan “surga” dalam pemrograman berbasis objek. Namun penggunaan penurunan kelas secara berlebihan akan menyulitkan pengembangan aplikasi di masa yang akan datang.
Setelah class diagram di atas, sekarang kita lanjutkan ke penerapannya pada sebuah script PHP seperti di bawah ini :
3 | abstract class SaklarImplementasi { |
4 | abstract function status_awal( $in_awal ); |
5 | abstract function status_akhir( $in_akhir ); |
8 | class SaklarKamar extends SaklarImplementasi { |
9 | function status_awal( $status_awal_in ) { |
10 | return '|||||' . $status_awal_in . '|||||' ; |
12 | function status_akhir( $status_akhir_in ) { |
13 | return '------' . $status_akhir_in . '------' ; |
17 | class SaklarDapur extends SaklarImplementasi { |
18 | function status_awal( $status_awal_in ) { |
19 | return $status_awal_in ; |
21 | function status_akhir( $status_akhir_in ) { |
22 | return strtoupper ( $status_akhir_in ); |
26 | class SaklarGarasi extends SaklarImplementasi { |
27 | function status_awal( $status_awal_in ) { |
28 | return 'garasi - ' . $status_awal_in ; |
30 | function status_akhir( $status_akhir_in ) { |
31 | return 'garasi - ' . strtoupper ( $status_akhir_in ); |
35 | abstract class Saklar { |
37 | private $status_akhir ; |
39 | function __construct( $status_awal_in , $status_akhir_in , $kode_in ) { |
40 | $this ->status_awal = $status_awal_in ; |
41 | $this ->status_akhir = $status_akhir_in ; |
42 | if ( $kode_in == 'dapur' ) { |
43 | $this ->kode = new SaklarDapur(); |
44 | } else if ( $kode_in == 'kamar' ) { |
45 | $this ->kode = new SaklarKamar(); |
46 | } else if ( $kode_in == 'garasi' ) { |
47 | $this ->kode = new SaklarGarasi(); |
50 | function status_awal() { |
51 | return $this ->kode->status_awal( $this ->status_awal); |
53 | function status_akhir() { |
54 | return $this ->kode->status_akhir( $this ->status_akhir); |
58 | class SaklarHidup extends Saklar { |
60 | return $this ->status_awal() . " -> " . $this ->status_akhir(); |
64 | class SaklarMati extends Saklar { |
66 | return $this ->status_akhir() . ' -> ' . $this ->status_awal(); |
69 | cetak( 'Lampu Kamar, mati -> hidup' ); |
70 | $saklar = new SaklarHidup( 'off' , 'on' , 'kamar' ); |
71 | cetak( $saklar ->hidupkan()); |
74 | cetak( 'Lampu Dapur, mati -> hidup' ); |
75 | $saklar = new SaklarHidup( 'off' , 'on' , 'dapur' ); |
76 | cetak( $saklar ->hidupkan()); |
79 | cetak( 'Lampu Kamar, hidup -> mati' ); |
80 | $saklar = new SaklarMati( 'off' , 'on' , 'kamar' ); |
81 | cetak( $saklar ->matikan()); |
84 | cetak( 'Lampu Dapur, hidup -> mati' ); |
85 | $saklar = new SaklarMati( 'off' , 'on' , 'dapur' ); |
86 | cetak( $saklar ->matikan()); |
89 | function cetak( $isi ) { |
0 komentar:
Posting Komentar