修飾模式 Decorator Pattern 修飾模式,或者稱裝飾者模式,為物件動態增加新的方法,就想像你最初的大頭菜沒有想過他會壞掉,某天突然覺得讓大頭菜壞掉好像很好玩,但你不能把整個大頭菜砍掉重練,所以你希望可以不改變既有的大頭菜,在大頭菜額外再套上新的功能,那就是壞掉。
UML
實作 首先我們會需要定義出最初始大頭菜的介面,以及其最初的功能。
TurnipsInterface.php
1 2 3 4 5 6 7 interface TurnipsInterface { public function calculatePrice ( ): int ; }
TurnipsService.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 class TurnipsService implements TurnipsInterface { protected $price ; protected $count ; public function __construct (int $price , int $count ) { $this ->price = $price ; $this ->count = $count ; } public function calculatePrice ( ): int { return $this ->price * $this ->count; } }
再來我們需要建立裝飾器(Decorator),來修飾我們後來添加的壞掉功能,並且把最初始的大頭菜丟進去,讓大頭菜直接壞掉,沒有壞掉就拿石頭丟他!
TurnipsDecorator.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 abstract class TurnipsDecorator implements TurnipsInterface { protected $turnips ; public function __construct (TurnipsInterface $turnips ) { $this ->turnips = $turnips ; } }
Turnips.php
1 2 3 4 5 6 7 8 9 10 11 12 13 class Turnips extends TurnipsDecorator { public function calculatePrice ( ): int { return $this ->turnips->calculatePrice (); } }
Spoiled.php
1 2 3 4 5 6 7 8 9 10 11 12 13 class Spoiled extends TurnipsDecorator { public function calculatePrice ( ): int { return 0 ; } }
測試 完成了大頭菜裝飾器之後,我們接下來要驗證前面所寫的裝飾器是否能夠正常運行,因此我們有幾個重要項目要來做測試:
測試正常的大頭菜是否可以賣鈴錢。
測試壞掉的大頭菜是否沒辦法賣鈴錢。
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 class DecoratorPatternTest extends TestCase { public function test_turnips ( ) { $service = new TurnipsService (100 , 40 ); $turnips = new Turnips ($service ); $this ->assertEquals (4000 , $turnips ->calculatePrice ()); } public function test_spoiled ( ) { $service = new TurnipsService (100 , 40 ); $turnips = new Spoiled ($service ); $this ->assertEquals (0 , $turnips ->calculatePrice ()); } }
最後測試的執行結果會獲得如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 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 ✔ ✔ ✔ ✔ ✔ ==> AdapterPatternTest ✔ ✔ ==> BridgePatternTest ✔ ✔ ✔ ==> CompositePatternTest ✔ ✔ ✔ ==> DataMapperTest ✔ ✔ ==> DecoratorPatternTest ✔ ✔ Time: 00:00.050, Memory: 6.00 MB OK (41 tests, 88 assertions)
完整程式碼 設計模式不難,找回快樂而已,以大頭菜為例。
參考文獻