装饰器模式,可以动态地添加修改类的功能。
一个类提供了一项功能,如果要修改并添加额外的功能,传统的编程模式需要写一个子类继承它,并重新实现类的方法。使用装饰器模式,仅需要在运行时添加一个装饰器对象即可实现,可以实现最大的灵活性。
<span>DrawDecorator</span>.php
<span style="color: #000000;">php namespace Baobab; </span><span style="color: #008000;">/*</span><span style="color: #008000;">* * Interface DrawDecorator * @package Baobab * 装饰器接口,定义两个方法,渲染画布之前和之后可添加额外的能力 </span><span style="color: #008000;">*/</span> <span style="color: #0000ff;">interface</span><span style="color: #000000;"> DrawDecorator{ </span><span style="color: #0000ff;">function</span><span style="color: #000000;"> beforeDraw(); </span><span style="color: #0000ff;">function</span><span style="color: #000000;"> afterDraw(); }</span>
<span>Canvas</span>.php
<span style="color: #000000;">php namespace Baobab; <br><span style="color: #008000;">/**</span><br><span style="color: #008000;">*Canvas类,绘制图形</span><br><span style="color: #008000;">**/</span><br> </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> Canvas { </span><span style="color: #0000ff;">public</span> <span style="color: #800080;">$data</span><span style="color: #000000;">; </span><strong><span style="color: #0000ff;">protected</span> <span style="color: #800080;">$decorators</span> = <span style="color: #0000ff;">array</span><span style="color: #000000;">(); </span></strong><span style="color: #008000;">//</span><span style="color: #008000;">Decorator</span> <span style="color: #0000ff;">function</span> init(<span style="color: #800080;">$width</span> = 20, <span style="color: #800080;">$height</span> = 10<span style="color: #000000;">) { </span><span style="color: #800080;">$data</span> = <span style="color: #0000ff;">array</span><span style="color: #000000;">(); </span><span style="color: #0000ff;">for</span>(<span style="color: #800080;">$i</span> = 0; <span style="color: #800080;">$i</span> $height; <span style="color: #800080;">$i</span>++<span style="color: #000000;">) { </span><span style="color: #0000ff;">for</span>(<span style="color: #800080;">$j</span> = 0; <span style="color: #800080;">$j</span> $width; <span style="color: #800080;">$j</span>++<span style="color: #000000;">) { </span><span style="color: #800080;">$data</span>[<span style="color: #800080;">$i</span>][<span style="color: #800080;">$j</span>] = '*'<span style="color: #000000;">; } } </span><span style="color: #800080;">$this</span>->data = <span style="color: #800080;">$data</span><span style="color: #000000;">; } </span><strong><span style="color: #0000ff;">function</span> addDecorator(DrawDecorator <span style="color: #800080;">$decorator</span><span style="color: #000000;">){ </span><span style="color: #800080;">$this</span>->decorators[] = <span style="color: #800080;">$decorator</span><span style="color: #000000;">; } </span><span style="color: #0000ff;">function</span><span style="color: #000000;"> beforeDraw(){ </span><span style="color: #0000ff;">foreach</span>(<span style="color: #800080;">$this</span>->decorators <span style="color: #0000ff;">as</span> <span style="color: #800080;">$decorator</span><span style="color: #000000;">){ </span><span style="color: #800080;">$decorator</span>-><span style="color: #000000;">beforeDraw(); } } </span><span style="color: #0000ff;">function</span><span style="color: #000000;"> afterDraw(){ </span><span style="color: #800080;">$decorators</span> = <span style="color: #008080;">array_reverse</span>(<span style="color: #800080;">$this</span>-><span style="color: #000000;">decorators); </span><span style="color: #0000ff;">foreach</span>(<span style="color: #800080;">$decorators</span> <span style="color: #0000ff;">as</span> <span style="color: #800080;">$decorator</span><span style="color: #000000;">){ </span><span style="color: #800080;">$decorator</span>-><span style="color: #000000;">afterDraw(); } } </span></strong><span style="color: #0000ff;">function</span><span style="color: #000000;"> draw() { </span><strong><span style="color: #800080;">$this</span>-><span style="color: #000000;">beforeDraw(); </span></strong><span style="color: #0000ff;">foreach</span>(<span style="color: #800080;">$this</span>->data <span style="color: #0000ff;">as</span> <span style="color: #800080;">$line</span><span style="color: #000000;">) { </span><span style="color: #0000ff;">foreach</span>(<span style="color: #800080;">$line</span> <span style="color: #0000ff;">as</span> <span style="color: #800080;">$char</span><span style="color: #000000;">) { </span><span style="color: #0000ff;">echo</span> <span style="color: #800080;">$char</span><span style="color: #000000;">; } </span><span style="color: #0000ff;">echo</span> "<br>\n"<span style="color: #000000;">; } </span><strong><span style="color: #800080;">$this</span>-></strong><span style="color: #000000;"><strong>afterDraw();</strong> } </span><span style="color: #0000ff;">function</span> rect(<span style="color: #800080;">$a1</span>, <span style="color: #800080;">$a2</span>, <span style="color: #800080;">$b1</span>, <span style="color: #800080;">$b2</span><span style="color: #000000;">) { </span><span style="color: #0000ff;">foreach</span>(<span style="color: #800080;">$this</span>->data <span style="color: #0000ff;">as</span> <span style="color: #800080;">$k1</span> => <span style="color: #800080;">$line</span><span style="color: #000000;">) { </span><span style="color: #0000ff;">if</span> (<span style="color: #800080;">$k1</span> $a1 or <span style="color: #800080;">$k1</span> > <span style="color: #800080;">$a2</span>) <span style="color: #0000ff;">continue</span><span style="color: #000000;">; </span><span style="color: #0000ff;">foreach</span>(<span style="color: #800080;">$line</span> <span style="color: #0000ff;">as</span> <span style="color: #800080;">$k2</span> => <span style="color: #800080;">$char</span><span style="color: #000000;">) { </span><span style="color: #0000ff;">if</span> (<span style="color: #800080;">$k2</span> $b1 or <span style="color: #800080;">$k2</span> > <span style="color: #800080;">$b2</span>) <span style="color: #0000ff;">continue</span><span style="color: #000000;">; </span><span style="color: #800080;">$this</span>->data[<span style="color: #800080;">$k1</span>][<span style="color: #800080;">$k2</span>] = ' '<span style="color: #000000;">; } } } }</span>
<span>ColorDrawDecorator</span>.php
<span style="color: #000000;">php namespace Baobab; <span style="color: #008000;">/**</span><br><span style="color: #008000;">*修改图形颜色的装饰器</span><br><span style="color: #008000;">*/ </span></span><span style="color: #0000ff;">class</span> ColorDrawDecorator <span style="color: #0000ff;">implements</span><span style="color: #000000;"> \Baobab\DrawDecorator{ </span><span style="color: #0000ff;">protected</span> <span style="color: #800080;">$color</span><span style="color: #000000;">; </span><span style="color: #0000ff;">function</span> __construct(<span style="color: #800080;">$color</span> = 'black'<span style="color: #000000;">){ </span><span style="color: #800080;">$this</span>->color = <span style="color: #800080;">$color</span><span style="color: #000000;">; } </span><span style="color: #0000ff;">function</span><span style="color: #000000;"> beforeDraw(){ </span><span style="color: #0000ff;">echo</span> "<div style='color: {<span style="color: #800080;">$this</span>->color};'>"<span style="color: #000000;">; }<br> </span><span style="color: #0000ff;">function</span><span style="color: #000000;"> afterDraw(){ </span><span style="color: #0000ff;">echo</span> "</div>"<span style="color: #000000;">; } }</span>
<span>SizeDrawDecorator</span>.php
<span style="color: #000000;">php namespace Baobab; <span style="color: #000000;"><span style="color: #008000;">/**<br><span style="color: #008000;">*修改图形大小的装饰器<br><span style="color: #008000;">*/ </span></span></span></span> </span><span style="color: #0000ff;">class</span> SizeDrawDecorator <span style="color: #0000ff;">implements</span><span style="color: #000000;"> \Baobab\DrawDecorator{ </span><span style="color: #0000ff;">protected</span> <span style="color: #800080;">$size</span><span style="color: #000000;">; </span><span style="color: #0000ff;">function</span> __construct(<span style="color: #800080;">$size</span> = '12px'<span style="color: #000000;">){ </span><span style="color: #800080;">$this</span>->size = <span style="color: #800080;">$size</span><span style="color: #000000;">; } </span><span style="color: #0000ff;">function</span><span style="color: #000000;"> beforeDraw() { </span><span style="color: #0000ff;">echo</span> "<div style='font-size: {<span style="color: #800080;">$this</span>->size};'>"<span style="color: #000000;">; }<br> </span><span style="color: #0000ff;">function</span><span style="color: #000000;"> afterDraw() { </span><span style="color: #0000ff;">echo</span> "</div>"<span style="color: #000000;">; } }</span>
index.php
<span style="color: #800080;">$canvas</span> = <span style="color: #0000ff;">new</span><span style="color: #000000;"> Baobab\Canvas(); </span><span style="color: #800080;">$canvas</span>-><span style="color: #000000;">init(); </span><span style="color: #800080;">$canvas</span>->rect(3, 6,4,12<span style="color: #000000;">); </span><span style="color: #800080;">$canvas</span>->addDecorator(<span style="color: #0000ff;">new</span> \Baobab\ColorDrawDecorator('blue'<span style="color: #000000;">)); </span><span style="color: #800080;">$canvas</span>->addDecorator(<span style="color: #0000ff;">new</span> \Baobab\SizeDrawDecorator('10px'<span style="color: #000000;">));<br>......<br>//可添加其他更多装饰器<br> </span><span style="color: #800080;">$canvas</span>->draw();