原型模式 Prototype Pattern 原型模式,你有些物件可能會需要建立很多一樣的物件,只是某些資料不太一樣而已,就有點像是每顆大頭菜都是一模一樣的物件,但可能因為來自不同的島,所以每顆大頭菜的差別只在於那起始購買的鈴錢不同。
UML
實作 首先我們需要以抽象類別的方式,來製作大頭菜的原型,並且定義好大頭菜的基本功能。
TurnipsPrototype.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 abstract class TurnipsPrototype { protected $category ; protected $price ; protected $count ; abstract public function __clone ( ) ; public function calculatePrice ( ): int { if (isset ($this ->price) && isset ($this ->count)) { return $this ->price * $this ->count; } else { return 0 ; } } }
再來建立健康的大頭菜、壞掉的大頭菜,並且引用大頭菜原型,這裡需要注意我們須要去實作 __clone
方法,這樣子才能讓大頭菜複製、貼上。
Turnips.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class Turnips extends TurnipsPrototype { protected $category = '大頭菜' ; public function __construct (int $price , int $count ) { $this ->price = $price ; $this ->count = $count ; } public function __clone ( ) { } }
SpoiledTurnips.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 class SpoiledTurnips extends TurnipsPrototype { protected $category = '壞掉的大頭菜' ; const SPOILED_PRICE = 0 ; public function __construct (int $price , int $count ) { $this ->price = self ::SPOILED_PRICE ; $this ->count = $count ; } public function __clone ( ) { } }
測試 最後要來驗證一下我們所寫的原型是否是正確的,所以這次的測試也比較簡單,原型模式著重於大頭菜可以被複製,每個被複製出來的大頭菜只有局部的內容不一樣,以最節省資源的方式,來處理重複性質高的物件。
建立大頭菜,並且複製 10 次,檢查每次大頭菜是否都是大頭菜,而且價格是正確的。
建立壞掉的大頭菜,並且複製 10 次,檢查每次大頭菜是否都是壞掉的大頭菜,而且都賣不了錢。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 class PrototypePatternTest extends TestCase { public function test_can_clone_turnips ( ) { $turnips = new Turnips (100 , 40 ); for ($i = 0 ; $i < 10 ; $i ++) { $_turnips = clone $turnips ; $this ->assertInstanceOf (Turnips ::class , $_turnips ); $this ->assertEquals (4000 , $_turnips ->calculatePrice ()); } } public function test_can_clone_spoiled_turnips ( ) { $turnips = new SpoiledTurnips (100 , 40 ); for ($i = 0 ; $i < 10 ; $i ++) { $_turnips = clone $turnips ; $this ->assertInstanceOf (SpoiledTurnips ::class , $_turnips ); $this ->assertEquals (0 , $_turnips ->calculatePrice ()); } } }
最後測試的執行結果會獲得如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 PHPUnit Pretty Result Printer 0.28.0 by Codedungeon and contributors. ==> Configuration: ~/php-design-pattern/vendor/codedungeon/phpunit-result-printer/src/phpunit-printer.yml PHPUnit 9.2.6 by Sebastian Bergmann and contributors. ==> AbstractFactoryTest ✔ ✔ ✔ ✔ ==> BuilderPatternTest ✔ ✔ ==> FactoryMethodTest ✔ ✔ ✔ ✔ ==> PoolPatternTest ✔ ✔ ==> PrototypePatternTest ✔ ✔ ==> SimpleFactoryTest ✔ ✔ ✔ ✔ ==> SingletonPatternTest ✔ ==> StaticFactoryTest ✔ ✔ ✔ ✔ ✔ Time: 00:00.050, Memory: 6.00 MB OK (24 tests, 68 assertions)
完整程式碼 設計模式不難,找回快樂而已,以大頭菜為例。
參考文獻