下面是针对“PHP设计模式(八)装饰器模式Decorator实例详解【结构型】”文章的完整攻略。
1. 什么是装饰器模式Decorator?
装饰器模式(Decorator)是一种结构型设计模式,它允许你动态地将对象添加到现有对象中。使用装饰器模式,可以将一个或多个装饰器包装在对象上,从而改变其行为。当需要动态地将对象添加到现有对象中或从对象中删除对象时,可以使用装饰器模式。
2. 装饰器模式的主要组成部分
装饰器模式包含以下组成部分:
- 抽象组件(Component):定义了一个抽象类,它是被装饰对象和所有具体装饰器的超类,提供了被装饰对象的基本行为,这些基本行为可以由具体装饰器来扩展。
- 具体组件(ConcreteComponent):实现抽象组件类的具体类,提供基本行为。
- 抽象装饰器(Decorator):定义了一个抽象类来装饰抽象组件或其具体子类,它可以是一个具体的类或一个抽象类。
- 具体装饰器(ConcreteDecorator):实现抽象装饰器类的具体类,可以为装饰对象添加新的行为或扩展现有行为。
3. 装饰器模式的实例说明
下面我们通过两个具体的示例说明装饰器模式的使用。
示例1:制作不同口味的咖啡
假设我们正在制作咖啡并需要为其添加不同的口味:白糖、红糖和牛奶。在这个例子中,咖啡是抽象组件,而白糖、红糖和牛奶是具体装饰器。
首先,我们定义抽象组件:
abstract class Coffee {
protected $description = "Unknown Coffee";
public function getDescription() {
return $this->description;
}
public abstract function cost();
}
接下来,我们定义具体组件:
class Espresso extends Coffee {
public function __construct() {
$this->description = "Espresso";
}
public function cost() {
return 1.99;
}
}
然后,我们定义抽象装饰器:
abstract class CoffeeDecorator extends Coffee {
public abstract function getDescription();
}
接下来,我们定义具体装饰器:
class Milk extends CoffeeDecorator {
protected $coffee;
public function __construct(Coffee $coffee) {
$this->coffee = $coffee;
}
public function getDescription() {
return $this->coffee->getDescription() . ", Milk";
}
public function cost() {
return $this->coffee->cost() + 0.20;
}
}
class Sugar extends CoffeeDecorator {
protected $coffee;
public function __construct(Coffee $coffee) {
$this->coffee = $coffee;
}
public function getDescription() {
return $this->coffee->getDescription() . ", Sugar";
}
public function cost() {
return $this->coffee->cost() + 0.10;
}
}
class RedSugar extends CoffeeDecorator {
protected $coffee;
public function __construct(Coffee $coffee) {
$this->coffee = $coffee;
}
public function getDescription() {
return $this->coffee->getDescription() . ", RedSugar";
}
public function cost() {
return $this->coffee->cost() + 0.15;
}
}
我们现在可以创建具体的咖啡对象,并动态地为其添加不同的装饰器:
$beverage = new Espresso();
echo $beverage->getDescription() . " $" . $beverage->cost();
$beverage = new Milk($beverage);
echo $beverage->getDescription() . " $" . $beverage-> cost();
$beverage = new RedSugar($beverage);
echo $beverage->getDescription() . " $" . $beverage->cost();
$beverage = new Sugar($beverage);
echo $beverage->getDescription() . " $" . $beverage->cost();
当我们执行这段代码时,输出结果如下:
Espresso $1.99
Espresso, Milk $2.19
Espresso, Milk, RedSugar $2.34
Espresso, Milk, RedSugar, Sugar $2.44
这说明我们成功地为咖啡添加了不同的口味。
示例2:动态添加属性到HTML标签
接下来,我们通过另一个示例来说明装饰器模式。假设我们需要动态地向HTML标签添加不同的属性,如class、id、style等。在此示例中,HTML标签是抽象组件,而属性是具体装饰器。
首先,我们定义抽象组件:
abstract class HtmlTag {
private $name;
private $attributes;
private $value;
public function __construct($name) {
$this->name = $name;
$this->attributes = array();
$this->value = "";
}
public function getName() {
return $this->name;
}
public function setAttribute($attribute, $value) {
$this->attributes[$attribute] = $value;
}
public function removeAttribute($attribute) {
unset($this->attributes[$attribute]);
}
public function setValue($value) {
$this->value = $value;
}
public function getValue() {
return $this->value;
}
public function getAttributes() {
return $this->attributes;
}
public abstract function render();
}
接下来,我们定义具体组件:
class HtmlInput extends HtmlTag {
public function __construct($name) {
parent::__construct($name);
}
public function render() {
$html = "<input type=\"text\" name=\"{$this->getName()}\" value=\"{$this->getValue()}\" ";
$attributes = $this->getAttributes();
foreach($attributes as $attribute => $value) {
$html .= "{$attribute}=\"{$value}\" ";
}
$html .= " />";
return $html;
}
}
然后,我们定义具体装饰器:
class HtmlClass extends HtmlTag {
private $component;
private $class;
public function __construct(HtmlTag $component, $class) {
$this->component = $component;
$this->class = $class;
}
public function render() {
$attributes = $this->component->getAttributes();
$attributes['class'] = $this->class;
$this->component->setAttributes($attributes);
return $this->component->render();
}
}
class HtmlId extends HtmlTag {
private $component;
private $id;
public function __construct(HtmlTag $component, $id) {
$this->component = $component;
$this->id = $id;
}
public function render() {
$attributes = $this->component->getAttributes();
$attributes['id'] = $this->id;
$this->component->setAttributes($attributes);
return $this->component->render();
}
}
我们现在可以创建具体的HTML对象,并动态地为其添加不同的属性:
$input = new HtmlInput("username");
$input->setValue("admin");
$input = new HtmlClass($input, "form-control");
$input = new HtmlId($input, "username");
echo $input->render();
当我们执行这段代码时,输出结果如下:
<input type="text" name="username" value="admin" class="form-control" id="username" />
这说明我们成功地为HTML标签动态添加了不同的属性。
4. 总结
本文通过以上两个示例详细讲解了装饰器模式的使用。要使用装饰器模式,需要遵循一些结构规则,并且需要理解抽象组件和装饰器之间的关系。如果需要动态地扩展一个对象,并且不能直接修改它的代码,那么应该考虑使用装饰器模式。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:PHP设计模式(八)装饰器模式Decorator实例详解【结构型】 - Python技术站