🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## 第10章 原型模式 ### 第一步:准备了1个画布的类 *D:\wamp\www\demo\oop\framework\Think\Canvas.php* ~~~ <?php namespace Think; class Canvas { public $data; protected $decorators = array(); //Decorator function init($width = 20, $height = 10) { $data = array(); for($i = 0; $i < $height; $i++) { for($j = 0; $j < $width; $j++) { $data[$i][$j] = '='; } } $this->data = $data; } function draw() { foreach($this->data as $line) { foreach($line as $char) { echo $char; } echo "<br />\n"; } } function rect($a1, $a2, $b1, $b2) { foreach($this->data as $k1 => $line) { if ($k1 < $a1 or $k1 > $a2) continue; foreach($line as $k2 => $char) { if ($k2 < $b1 or $k2 > $b2) continue; $this->data[$k1][$k2] = '+'; } } } } ~~~ 在 `init` 方法中循环输出一张画布,类似这样的初始化操作,其实都是比较耗费资源的。 *D:\wamp\www\demo\oop\framework\index.php* ~~~ $canvas1 = new Think\Canvas(); $canvas1->init(); $canvas1->rect(2,7,2,18); $canvas1->draw(); echo "<hr/>"; $canvas2 = new Think\Canvas(); $canvas2->init(); $canvas2->draw(); ~~~ 效果图: ![](./img/10/01.png) ## 第二步:使用原型 我们可以看出,每次new这个对象,其实很耗费资源,这里我们来使用 `clone` 原型对象。 ~~~ // 生成1个原型对象 $prototype = new Think\Canvas(); $prototype->init(); // $canvas1 = new Think\Canvas(); $canvas1 = clone($prototype); $canvas1->rect(2,7,2,18); $canvas1->draw(); echo "<hr/>"; $canvas2 = clone($prototype); $canvas2->rect(3,5,2,10); $canvas2->draw(); ~~~ 总结:像这个原型只有1个初始化方法而已,像比较复杂的类,还有如:设置颜色,大小等等,越复杂的类,使用原型对象就越能够节省资源。 ### 第二步:创建1个装饰器接口 *D:\wamp\www\demo\oop\framework\Think\DrawDecorator.php* ~~~ <?php namespace Think; // 声明1个装饰器接口 interface DrawDecorator { function beforeDraw(); function afterDraw(); } ~~~ ### 第三步:添加装饰器方法 *D:\wamp\www\demo\oop\framework\Think\Canvas.php* ~~~ function draw() { $this->beforeDraw(); // 装饰器方法 foreach($this->data as $line) { foreach($line as $char) { echo $char; } echo "<br />\n"; } $this->afterDraw(); // 装饰器方法 } ~~~ 添加装饰器: ~~~ protected $decorators = array(); ... // 添加装饰器 function addDecorator(DrawDecorator $decorator) { $this->decorators[] = $decorator; } // Draw装饰方法1 function beforeDraw() { foreach($this->decorators as $decorator) { $decorator->beforeDraw(); } } // Draw装饰方法2 function afterDraw() { $decorators = array_reverse($this->decorators); foreach($decorators as $decorator) { $decorator->afterDraw(); } } ~~~ ### 第三步:创建1个颜色的装饰器,1个大小的装饰器 *D:\wamp\www\demo\oop\framework\Think\ColorDrawDecorator.php* ~~~ <?php namespace Think; class ColorDrawDecorator implements DrawDecorator { protected $color = 'black'; function __construct($color) { $this->color = $color; } function beforeDraw() { echo "<div style='color:" . $this->color . "'>"; } function afterDraw() { echo "</div>"; } } ~~~ *D:\wamp\www\demo\oop\framework\Think\SizeDrawDecorator.php* ~~~ <?php namespace Think; class SizeDrawDecorator implements DrawDecorator { protected $size = 'black'; function __construct($size) { $this->size = $size; } function beforeDraw() { echo "<div style='font-size:" . $this->size . "'>"; } function afterDraw() { echo "</div>"; } } ~~~ ### 第四步:装饰器的使用 *D:\wamp\www\demo\oop\framework\index.php* ~~~ // 装饰模式的使用 $canvas1 = new Think\Canvas(); $canvas1->init(); // 添加装饰器 $canvas1->addDecorator(new Think\ColorDrawDecorator('green')); $canvas1->addDecorator(new Think\SizeDrawDecorator('20px')); $canvas1->rect(2,7,2,18); $canvas1->draw(); ~~~