Observer Pattern
I. Pengantar
Seperti namanya,observer patternberfungsi untuk melakukan ob- servasi terhadap suatuevent.Event yang dimaksud adalah sebuah interesting point dari suatu aplikasi. Dalamobserver pattern, jum- lahobserverbisa tidak terbatas.
Observer patternbiasanya digunakan untuk membuat sebuah ap- likasi dapat di-extendolehdeveloperlainnya tanpa harus melakukan perubahan padasource code. Cara ini biasanya disebuthooking.
Contoh penerapanobserver patternsangat banyak. Bila Anda nanti memutuskan untuk menggunakanframework, maka hampir semua framework menggunakanpattern ini. Biasanya dapatframework, Observer patterndisebut jugaevent dispatcher.
1 <?php 2
3 namespace ObserverPattern;
4
5 interface ObserverInterface 6 {
7 public function update(SubjectInterface $subject);
8 }
1 <?php 2
3 namespace ObserverPattern;
4
5 interface SubjectInterface 6 {
7 public function getName();
8
9 public function attach(ObserverInterface $observer);
10
11 public function detach(ObserverInterface $observer);
12
13 public function notify();
14
15 public function getState();
16 }
• Observer
Observer Pattern 151
1 <?php 2
3 namespace ObserverPattern;
4
5 class Observer implements ObserverInterface 6 {
7 public function update(SubjectInterface $subject)
8 {
9 echo sprintf('Sekarang %s lagi %s', $subject->g\
10 etName(), $subject->getState()).PHP_EOL;
11 }
12 }
1 <?php 2
3 namespace ObserverPattern;
4
5 class OtherObserver implements ObserverInterface 6 {
7 public function update(SubjectInterface $subject)
8 {
9 echo sprintf('%s sedang %s', $subject->getName(\
10 ), $subject->getState()).PHP_EOL;
11 }
12 }
• Subject
1 <?php 2
3 namespace ObserverPattern;
4
5 class Subject implements SubjectInterface 6 {
7 private $observers = array();
8
9 private $state;
10
11 private $name;
12
13 public function __construct($name)
14 {
15 $this->name = $name;
16 }
17
18 public function getName()
19 {
20 return $this->name;
21 }
22
23 public function attach(ObserverInterface $observer)
24 {
25 $this->observers[get_class($observer)] = $obser\
26 ver;
27 }
28
29 public function detach(ObserverInterface $observer)
30 {
31 $key = get_class($observer);
32 if (array_key_exists($key, $this->observers)) { 33 unset($this->observers[$key]);
34 }
35 }
Observer Pattern 153
36
37 public function notify()
38 {
39 foreach($this->observers as $observer) { 40 $observer->update($this);
41 }
42 }
43
44 public function update($state)
45 {
46 $this->state = $state;
47 $this->notify();
48 }
49
50 public function getState()
51 {
52 return $this->state;
53 }
54 }
• composer.json
1 {
2 "autoload": { 3 "psr-4": { 4 "": ""
5 }
6 }
7 }
• index.php
1 <?php 2
3 require __DIR__.'/vendor/autoload.php';
4
5 use ObserverPattern\Subject;
6 use ObserverPattern\Observer;
7 use ObserverPattern\OtherObserver;
8
9 $subject = new Subject('Mawar');
10
11 $observer = new Observer();
12 $otherObserver = new OtherObserver();
13
14 $subject->attach($observer);
15 $subject->attach($otherObserver);
16
17 $subject->update('Pergi ke kampus');
18 $subject->update('Pergi ke kantin');
19
20 $subject->detach($otherObserver);//$otherObserver tidak\
21 lagi ikut mengamati 22
23 $subject->update('Pulang kuliah');
Setelahcomposer update dan Anda menjalankan program diatas, maka hasilnya adalah sebagai berikut:
Observer Pattern
Bila Anda perhatikan, inti dariobserver patternada padamethod
Observer Pattern 155
update(), dimana pada method tersebut dipanggil juga method
notify().
1 public function update($state)
2 {
3 $this->state = $state;
4 $this->notify();
5 }
Disinilahchaning yang saya maksud diatas.
I. Pengantar
Factory patternadalah sebuahpatternyang bertujuan untuk melakukan sentralisasi dalam pembuatanobject. Sama sepertiobserver pattern, patternini juga banyak digunakan olehframework.
Keuntungan darifactory patternadalah ketika Anda perlu melakukan rename atau mengganti suatu classdalam factory pattern, Anda cukup menggantinya disatu tempat. Anda tidak perlu menggu- nakan fitursearch and replaceyang ada pada IDE atau Editor untuk mengetahui dimana sajaclasstersebut dipanggil.
II. Implementasi
Implementasifactory patternterbilang lebih mudah dibandingkan denganobserver patternyang sebelumnya. Untuk lebih jelas, per- hatikan contoh berikut:
• Interface
156
Factory Pattern 157
1 <?php 2
3 namespace Factory;
4
5 interface KendaraanInterface 6 {
7 public function gas();
8 }
• Factory
1 <?php 2
3 namespace Factory;
4
5 class Factory 6 {
7 protected $kendaraan;
8
9 public function __construct()
10 {
11 $this->kendaraan = array(
12 'sepeda' => Sepeda::class, 13 'motor' => Motor::class, 14 'mobil' => Mobil::class,
15 );
16 }
17
18 public function create($type)
19 {
20 if (!array_key_exists($type, $this->kendaraan))\
21 {
22 throw new \InvalidArgumentException(sprintf\
23 ('Kendaraan dengan tipe %s tidak ditemukan', $type));
24 }
25 $className = $this->kendaraan[$type];
26
27 return new $className();
28 }
29 }
• Kendaraan
1 <?php 2
3 namespace Factory;
4
5 class Sepeda implements KendaraanInterface 6 {
7 public function gas()
8 {
9 return 'Wus wus wus...';
10 }
11 }
1 <?php 2
3 namespace Factory;
4
5 class Motor implements KendaraanInterface 6 {
7 public function gas()
8 {
9 return 'Brum... brum... brum...';
10 }
11 }
Factory Pattern 159
1 <?php 2
3 namespace Factory;
4
5 class Mobil implements KendaraanInterface 6 {
7 public function gas()
8 {
9 return 'Ngueeeeeeeennnnnnggggggggggggg';
10 }
11 }
• composer.json
1 {
2 "autoload": { 3 "psr-4": { 4 "": ""
5 }
6 }
7 }
• index.php
1 <?php 2
3 require __DIR__.'/vendor/autoload.php';
4
5 use Factory\Factory;
6
7 $factory = new Factory();
8 $sepeda = $factory->create('sepeda');
9 $motor = $factory->create('motor');
10 $mobil = $factory->create('mobil');
11
12 echo $sepeda->gas();
13 echo PHP_EOL;
14
15 echo $motor->gas();
16 echo PHP_EOL;
17
18 echo $mobil->gas();
19 echo PHP_EOL;
Bagaimana? Lebih simpel bukan? Bila kita jalankan program diatas maka hasilnya adalah sebagai berikut:
Factory Pattern
Facade Pattern
I. Pengantar
Facade Patternadalah sebuahpatternyang bertujuan untuk menyem- bunyikan kompleksitas sebuah proses.Patternini sangat terkenal pada pengguna framework Laravel digunakan pada core Laravel itu sendiri.
Keuntungan menggunakanpatternini adalahcalleratau pengguna tidak perlu mengetahui kompleksitas darisub system atau proses yang terjadi dalam internalmethod.
II. Implementasi
Dalam implementasi kali ini, kita akan membuat sebuah contoh yang cukup panjang. Kita akan membuatinterfaceserta beberapa classimplementasinya sebagai berikut:
• Interface
161
1 <?php 2
3 namespace Facade;
4
5 interface CalculableInterface 6 {
7 public function setProduct(Product $product);
8
9 public function calculate();
10 }
• Implementasi
1 <?php 2
3 namespace Facade;
4
5 class Order implements CalculableInterface 6 {
7 /**
8 * @var Product
9 */
10 private $product;
11
12 /**
13 * @param Product $product
14 */
15 public function setProduct(Product $product)
16 {
17 $this->product = $product;
18 }
19
20 public function calculate()
21 {
Facade Pattern 163
22 // Anggap saja ini proses yang rumit dan panjang
23 }
24 }
1 <?php 2
3 namespace Facade;
4
5 class AdminFee implements CalculableInterface 6 {
7 /**
8 * @var Product
9 */
10 private $product;
11
12 /**
13 * @param Product $product
14 */
15 public function setProduct(Product $product)
16 {
17 $this->product = $product;
18 }
19
20 public function calculate()
21 {
22 // Anggap saja ini proses yang rumit dan panjang
23 }
24 }
1 <?php 2
3 namespace Facade;
4
5 class Discount implements CalculableInterface 6 {
7 /**
8 * @var Product
9 */
10 private $product;
11
12 /**
13 * @param Product $product
14 */
15 public function setProduct(Product $product)
16 {
17 $this->product = $product;
18 }
19
20 public function calculate()
21 {
22 // Anggap saja ini proses yang rumit dan panjang
23 }
24 }
1 <?php 2
3 namespace Facade;
4
5 class ShippingFee implements CalculableInterface 6 {
7 /**
8 * @var Product
9 */
Facade Pattern 165
10 private $product;
11
12 /**
13 * @param Product $product
14 */
15 public function setProduct(Product $product)
16 {
17 $this->product = $product;
18 }
19
20 public function calculate()
21 {
22 // Anggap saja ini proses yang rumit dan panjang
23 }
24 }
• Product-nya
1 <?php 2
3 namespace Facade;
4
5 class Product 6 {
7 /**
8 * @var int
9 */
10 private $qty;
11
12 /**
13 * @var string
14 */
15 private $name;
16
17 /**
18 * @var int
19 */
20 private $price;
21
22 /**
23 * @return int
24 */
25 public function getQty()
26 {
27 return $this->qty;
28 }
29
30 /**
31 * @param int $qty
32 */
33 public function setQty($qty)
34 {
35 $this->qty = $qty;
36 }
37
38 /**
39 * @return string
40 */
41 public function getName()
42 {
43 return $this->name;
44 }
45
46 /**
47 * @param string $name
48 */
49 public function setName($name)
50 {
51 $this->name = $name;
Facade Pattern 167
52 }
53
54 /**
55 * @return int
56 */
57 public function getPrice()
58 {
59 return $this->price;
60 }
61
62 /**
63 * @param int $price
64 */
65 public function setPrice($price)
66 {
67 $this->price = $price;
68 }
69 }
Dariclass-classdiatas, kita akan membuatcallerdengan dua pen- dekatan. Pertama tanpa facade pattern dan kedua denganfacade pattern agar kelihatan perbedaannya. Untuk yang tidak menggu- nakanfacade pattern cukup mudah, berikut adalahcode pemang- gilnya.
1 <?php 2
3 require __DIR__.'/vendor/autoload.php';
4
5 use Facade\Product;
6 use Facade\AdminFee;
7 use Facade\Discount;
8 use Facade\Order;
9 use Facade\ShippingFee;
10
11 $product = new Product();
12 $product->setQty(1);
13 $product->setName('Facade Product');
14 $product->setPrice(10000);
15
16 $order = new Order();
17 $order->setProduct($product);
18 $order->calculate();
19
20 $discount = new Discount();
21 $discount->setProduct($product);
22 $discount->calculate();
23
24 $adminFee = new AdminFee();
25 $adminFee->setProduct($product);
26 $adminFee->calculate();
27
28 $shippingFee = new ShippingFee();
29 $shippingFee->setProduct($product);
30 $shippingFee->calculate();
Code diatas terlihat simple dan tidak ada masalah bukan? Tapi sebenarnya,codediatas bisa menjadi bermasalah jika dalam pener- apandiscountatau lainnya sudah mulai ada syarat-syarat tertentu sehingga akan banyakif nantinya disitu.
Dan semakin banyak if disana maka caller pun akan memiliki kompleksitas tinggi dan makin lama akan makin sulit di-maintain.
Untuk mengurangi kompleksitas pada pemanggil, maka kita bisa menggunakanfacade pattern. Dan berikut adalah contohnya:
• Facade Class
Facade Pattern 169
1 <?php 2
3 namespace Facade;
4
5 class OrderFacade 6 {
7 private $order;
8
9 private $discount;
10
11 private $adminFee;
12
13 private $shippingFee;
14
15 public function __construct()
16 {
17 $this->order = new Order();
18 $this->discount = new Discount();
19 $this->adminFee = new AdminFee();
20 $this->shippingFee = new ShippingFee();
21 }
22
23 public function setProduct(Product $product)
24 {
25 $this->order->setProduct($product);
26 $this->discount->setProduct($product);
27 $this->adminFee->setProduct($product);
28 $this->shippingFee->setProduct($product);
29 }
30
31 public function createOrder()
32 {
33 //Ceritanya ada pengecekan ini dan itu 34
35 $this->order->calculate();
36 $this->discount->calculate();
37 $this->adminFee->calculate();
38 $this->shippingFee->calculate();
39
40 //Kompleks banget lah pokoknya
41 }
42 }
• Pemanggilnya
1 <?php 2
3 require __DIR__.'/vendor/autoload.php';
4
5 use Facade\Product;
6 use Facade\OrderFacade;
7
8 $product = new Product();
9 $product->setQty(1);
10 $product->setName('Facade Product');
11 $product->setPrice(10000);
12
13 $facade = new OrderFacade();
14 $facade->setProduct($product);
15 $facade->createOrder();
Pada code diatas, jika suatu saat ada perubahan syarat discount atau lainnya maka Anda tidak perlu merubahcodepada pemanggil.
Anda cukup merubahnya padaclassFacadeOrdersehingga kom- pleksitas pada pemanggil bisa dikurangi secara signifikan.
Code-code diatas ketika dijalankan memang tidak akan mengelu- arkan output apapun, namun yang ingin saya sampaikan adalah bahwa konsep facade pattern ini akan memudahkan kita ketika
Facade Pattern 171 menangani kompleksitas seperti pada prosescheckoutpada sistem e-commerce.
Bila biasa Anda menerapkan prinsip hajar bleh, maka dengan memahamifacade patternini, Anda dapat menerapkan solusi yang berbeda dan lebihmaintainable.
Sederhana
I. Pengantar
Setelah kita belajar tentang OOP hinggadesign pattern, maka saat- nya kita mencoba mengimplementasikan semua yang kita pelajari kedalam sebuah aplikasi yangreal.
Sebagaifinal project, kita akan membuat sebuahframeworkseder- hana berbasis OOP dan menggunakancomposersebagaimana yang telah kita pelajari sebelumnya.