装饰模式的用途:
装饰模式通常用于为已有的功能动态的添加更多的功能。
当系统需要更新功能时,通常是向旧类中添加新的代码,而这些代码只是用于装饰原有类的核心职责和主要行为,这样的话就是在主类中添加新的字段、新的代码、新的逻辑,而这些新东西只是为了满足一些在特定情况才会执行到的需求。这样的话就会增加主类复杂度。而且不满足开闭原则。
但是装饰模式就提出了一种非常好的解决办法。它把每个要装饰的功能都放在单独的一个类中,并让这个类包装所需要装饰的对象,这样的话在执行时候,客户代码可以在运行时根据需要有选择的按顺序的用装饰功能包装对象。
装饰模式的具体实现
先上类图吧,这样大家看的更清晰一点:
Component是定义一个对象接口,可以给这些对象动态的添加职责。ConcreteComponent是定义了一个具体对象,也可以给这个对象添加一些职责。Decorator,装饰抽象类,继承Component,从外类来扩展Component类的功能,但对于Component来说,是无需知道Decorator的存在的。至于ConcreteDecorator就是具体装饰对象,起到给Component添加职责的功能。
看看代码吧:
abstract class Component{
public abstract function Operation();
}
class ConcreteComponent extends Component{
public function Operation(){
echo"具体对象操作";
}
}
abstract class Decorator extends Component{
protected $component;
public function SetComponent($com){//设置Component
$this->component=$com;
}
public function Operation(){//重写Operation(),实际执行的是Component的Operation()
if ($this->component != null){
$this->component->Operation();
}
}
}
class ConcreteDecoratorA extends Decorator{
private $addedState;//本类独有的功能,以区别ConcreteDecoratorB
public function Operation(){
parent::Operation();
$this->addedState="New State";
echo "具体装饰对象A的操作";
}
}
class ConcreteDecoratorB extends Decorator{
public function Operation(){
parent::Operation();//首先运行原Component的Operation(),再执行本类的功能,如addedState,相当于对原Component进行装饰
$this->AddedBehavior();
echo "具体装饰对象b的操作";
}
private function AddedBehavior(){
}
}
$c=new ConcreteComponent();
$d1=new ConcreteDecoratorA();
$d2=new ConcreteDecoratorB();
$d1->SetComponent($c);
echo "<br/>";
$d2->SetComponent($d1);
$d2->Operation();
装饰模式只是利用SetComponent来对对象进行包装,这样每个装饰对象的实现就和如何使用这个对象分离开来了,每个装饰对象只关心自己的功能,不需要关心如何被添加到对象链当中。
这样是不是大家清楚了很多呀。那么接下来我再给大家上个例子吧,让大家了解的更清楚一些。
我要实现这样一个功能:
需求:
1、按一定格式输出 (输出:格式|留言内容);
2、按一定格式(满足特定需求)例如:针对某一些留言,我需要过滤html标签(注意:不是过滤所有留言的,只是一小部分留言)(输出:原始格式|过滤HTML标签|留言内容)
大家可以想一下,然后再看后面的代码。
abstract class MessageBoardHandler
{
public function __construct(){}
abstract public function filter($msg);
}
class MessageBoard extends MessageBoardHandler
{
public function filter($msg)
{
return "处理留言板上的内容|".$msg;
}
}
class MessageBoardDecorator extends MessageBoardHandler
{
private $_handler = null;
public function __construct($handler)
{
parent::__construct();
$this->_handler = $handler;
}
public function filter($msg)
{
return $this->_handler->filter($msg);
}
}
// 过滤html
class HtmlFilter extends MessageBoardDecorator
{
public function __construct($handler)
{
parent::__construct($handler);
}
public function filter($msg)
{
return "过滤掉HTML标签|".parent::filter($msg);; // 过滤掉HTML标签的处理 这时只是加个文字 没有进行处理
}
}
// 过滤敏感词
class SensitiveFilter extends MessageBoardDecorator
{
public function __construct($handler)
{
parent::__construct($handler);
}
public function filter($msg)
{
return "过滤掉敏感词|".parent::filter($msg); // 过滤掉敏感词的处理 这时只是加个文字 没有进行处理
}
}
$obj = new HtmlFilter(new SensitiveFilter(new MessageBoard()));
echo $obj->filter("一定要学好装饰模式!<br/>");
本文借鉴程杰老师写的《大话设计模式》一书,脚本之家的装饰模式一例子。