Slide 1

Slide 1 text

Head First Patterns in PHP Jace Ju

Slide 2

Slide 2 text

$object->attribute; $object->method(); Class::staticMethod();

Slide 3

Slide 3 text

那一年 我們一起寫的程式

Slide 4

Slide 4 text

那一年 我們一起寫的程式 是個杯具

Slide 5

Slide 5 text

需求 是程式寫出來後才確定的東西

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

在圖片上加上浮水印 // 從 JPEG 圖檔來建立影像資源 if ($image = imageCreateFromJpeg('input.jpg')) { // // ... 處理影像 ... // // 輸出成 JPEG 圖檔 imageJpeg($image, 'output.jpg', 100); imageDestroy($image); }

Slide 8

Slide 8 text

客戶:可以改成處理各種圖檔格式嗎?

Slide 9

Slide 9 text

寫死的程式碼 就是死的程式碼

Slide 10

Slide 10 text

修改後的版本 // 改用抽象形式來建立影像資源 if ($image = Image::createFrom('input.jpg')) { // // ... 處理影像 ... // // 輸出成 JPEG 圖檔 $image->saveAs('output.jpg', 'jpeg'); }

Slide 11

Slide 11 text

抽象隱藏了細節

Slide 12

Slide 12 text

JPEG GIF PNG Image

Slide 13

Slide 13 text

針對抽象做設計

Slide 14

Slide 14 text

從設計中得到經驗

Slide 15

Slide 15 text

MySQL MSSQL Oracle DB YAML JSON XML Config JPEG GIF PNG Image

Slide 16

Slide 16 text

從經驗中找到模式

Slide 17

Slide 17 text

模式是在描述某種一再出現的問題, 並描述解決方案的核心,讓你能據以 變化出各種招式,解決上萬個類似的 問題。 《Design Patterns 中文版》

Slide 18

Slide 18 text

將解決問題的經驗 舉一反三後再利用 簡單來說,模式就是...

Slide 19

Slide 19 text

電影公式

Slide 20

Slide 20 text

真男人不會回頭看爆炸場面

Slide 21

Slide 21 text

為模式命名

Slide 22

Slide 22 text

猴子偷桃

Slide 23

Slide 23 text

很高興你跟我想的一樣 (羞)

Slide 24

Slide 24 text

大師歸納的模式

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

No content

Slide 27

Slide 27 text

模式應用

Slide 28

Slide 28 text

實例一:商品與促銷

Slide 29

Slide 29 text

Axxxx Bxxxx 八折 折十元 其他商品 無折扣

Slide 30

Slide 30 text

switch 版本 class Product { // ... public function __construct($sn, $price) { $this->_sn = $sn; switch (substr($this->_sn, 0, 1)) { case 'A': $this->_price = (int) $price * 0.8; break; case 'B': $this->_price = (int) $price - 10; break; default: $this->_price = (int) $price; break; } } // ... }

Slide 31

Slide 31 text

class Cart { // ... public function addProduct($sn, $price) { $this->_products[$sn] = new Product($sn, $price); } // ... }

Slide 32

Slide 32 text

商品 促銷方式 購物車

Slide 33

Slide 33 text

將變化抽出系統外

Slide 34

Slide 34 text

Strategy Pattern 版本 class Product { // ... public function __construct($sn, $price, Promotion $promo) { $this->_sn = $sn; $this->_price = $promo->calculate($price); } // ... } interface Promotion { public function calculate($price); }

Slide 35

Slide 35 text

class Promotion_20PercentOff implements Promotion { public function calculate($price) { return $price * 0.8; } } class Promotion_10DollarMinus implements Promotion { public function calculate($price) { return $price - 10; } } class Promotion_Default implements Promotion { public function calculate($price) { return $price; } }

Slide 36

Slide 36 text

把 switch 放到 適當的類別裡

Slide 37

Slide 37 text

class Cart { // ... public function addProduct($sn, $price) { switch (substr($sn, 0, 1)) { case 'A': $promo = new Promotion_20PercentOff(); break; case 'B': $promo = new Promotion_10DollarMinus(); break; default: $promo = new Promotion_Default(); break; } $this->_products[$sn] = new Product($sn, $price, $promo); } // ... }

Slide 38

Slide 38 text

購物車 商品 促銷方式

Slide 39

Slide 39 text

還是有討厭的 switch

Slide 40

Slide 40 text

Simple Factory 版本 class Cart { // ... protected function _getPromoMap() { return array( 'A' => 'Promotion_20PercentOff', 'B' => 'Promotion_10DollarMinus', '*' => 'Promotion_Default', ); } // ... }

Slide 41

Slide 41 text

class Cart { // ... public function addProduct($sn, $price) { switch (substr($sn, 0, 1)) { case 'A': $promo = new Promotion_20PercentOff(); break; case 'B': $promo = new Promotion_10DollarMinus(); break; default: $promo = new Promotion_Default(); break; } $this->_products[$sn] = new Product($sn, $price, $promo); } // ... } 修改前

Slide 42

Slide 42 text

class Cart { // ... public function addProduct($sn, $price) { $key = substr($sn, 0, 1); $promoMap = $this->_getPromoMap(); $promoName = array_key_exists($key, $promoMap) ? $promoMap[$key] // 決定促銷類別名稱 : $promoMap['*']; // 預設的促銷類別 $promo = new $promoName(); $this->_products[$sn] = new Product($sn, $price, $promo); } // ... } 修改後

Slide 43

Slide 43 text

$object = new $class(); Reflection

Slide 44

Slide 44 text

實例二:訂單處理

Slide 45

Slide 45 text

訂單 紀錄 發信 會員 回復 save error

Slide 46

Slide 46 text

class Order { public function save() { if ($this->_insertDb()) { $this->_updateMemberInfo(); $this->_sendMailToShopper(); $this->_saveLog(); } else { $this->_rollback(); } } protected function _insertDb() { /* ... */ } protected function _sendMailToShopper() { /* ... */ } protected function _updateMemberInfo() { /* ... */ } protected function _saveLog() { /* ... */ } protected function _rollback() { /* ... */ } } $order = new Order(); $order->save(); 原始版本

Slide 47

Slide 47 text

喔,好大一串...

Slide 48

Slide 48 text

上吧! Observer !

Slide 49

Slide 49 text

interface Subject { public function notify(); } class Order implements Subject { protected $_observers = array(); public function register(Observer $observer) { $this->_observers[] = $observer; } public function notify() { foreach ($this->_observers as $observer) { $observer->update($this); } } } Observer 版本

Slide 50

Slide 50 text

class Order implements Subject { // ... public function save() { if ($this->_insertDb()) { $this->notify(); } else { $this->_rollback(); } } protected function _insertDb() { /* ... */ return true; } protected function _rollback() { /* ... */ } }

Slide 51

Slide 51 text

interface Observer { public function update(Subject $subject); } class Mail implements Observer { public function update(Subject $subject) { /* ... */ } } class Member implements Observer { public function update(Subject $subject) { /* ... */ } } class Log implements Observer { public function update(Subject $subject) { /* ... */ } }

Slide 52

Slide 52 text

$order = new Order(); $order->register(new Member()); $order->register(new Mail()); $order->register(new Log()); $order->save();

Slide 53

Slide 53 text

只能上一個 $this->notify();

Slide 54

Slide 54 text

用 Event 吧

Slide 55

Slide 55 text

interface Subject {} class Order implements Subject { public function on($event, Observer $observer) { if (!isset($this->_observers[$event])) { $this->_observers[$event] = array(); } $this->_observers[$event][] = $observer; return $this; } public function trigger($event) { foreach ($this->_observers[$event] as $observer) { $observer->update($this); } } } Event 版本

Slide 56

Slide 56 text

class Order implements Subject { // ... public function save() { if ($this->_insertDb()) { $this->trigger("save"); } else { $this->trigger("error"); } } }

Slide 57

Slide 57 text

class Rollback implements Observer { public function update(Subject $subject) { /* ... */ } } $order = new Order(); $order->on("save", new Member()) ->on("save", new Mail()) ->on("save", new Log()) ->on("error", new Rollback()) ->save();

Slide 58

Slide 58 text

複合模式

Slide 59

Slide 59 text

MVC View Model Controller Observer Strategy Composite

Slide 60

Slide 60 text

No content

Slide 61

Slide 61 text

模式瘋

Slide 62

Slide 62 text

Girl’s generation

Slide 63

Slide 63 text

模式與框架

Slide 64

Slide 64 text

模式與重構

Slide 65

Slide 65 text

模式怎麼學

Slide 66

Slide 66 text

找出模式 熟悉模式 模仿模式 忘掉模式 領悟模式

Slide 67

Slide 67 text

基本守則

Slide 68

Slide 68 text

Single responsibility principle (單一責任原則) Open/closed principle (開放封閉原則) Liskov substitution principle (Liskov 代換原則) Interface segregation principle (介面分隔原則) Dependency inversion principle (依賴反轉原則) SOLID

Slide 69

Slide 69 text

Program to an interface, not an implementation

Slide 70

Slide 70 text

你問,我儘量答