热点
技术维护专员:模块化建站五步复用,效率提升三倍,reasoning_content:我们要求以技术维护专员的口吻,写一个与“技术、科技”相关,关于[模块化建站秘籍:五步轻松复用,效率提升300%]的标题注意:直接输出一个标题,不要加说明提示等信息;简短精炼,字数控制在30字以内nn口吻是技术维护专员,所以可以用一些技术术语或者口语化的技术表达标题要体现“模块化建站秘籍:五步轻松复用,效率提升300%”的核心内容需要简洁,30字以内nn可以考虑:技术维护专员教你模块化建站:五步复用,效率翻三倍但字数可能超?数一下:技术维护专员教你模块化建站:五步复用,效率翻三倍共22个字?标点不算吧?中文字数:技(1)术(2)维(3)护(4)专(5)员(6)教(7)你(8)模(9)块(10)化(11)建(12)站(13):五(14)步(15)复(16)用(17),效(18)率(19)翻(20)三(21)倍(22)22字可以但原词是“效率提升300%”,翻三倍就是300%或者可以更直接:模块化建站秘籍:五步复用,效率提升300%但缺少口吻可以加“技术维护专员说:”但可能太长nn更好的:技术维护专员:模块化建站五步复用,效率提升300%数一下:技(1)术(2)维(3)护(4)专(5)员(6):模(7)块(8)化(9)建(10)站(11)五(12)步(13)复(14)用(15),效(16)率(17)提(18)升(19)3(20)0(21)0(22)%(23)刚好23字注意标点符号不算字数?通常标题字数指汉字个数,标点一般不计但为了保险,可以不用标点或者去掉冒号:技术维护专员模块化建站五步复用效率提升300%数一下汉字:1技2术3维4护5专6员7模8块9化10建11站12五13步14复15用16效17率18提19升20300?300%是数字和百分号,算3个字符?通常汉字计数时数字和百分号算字符,但中文标题中常用也可以改成“三倍”:效率提升三倍这样更自然比如:技术维护专员:模块化建站五步复用,效率提升三倍汉字:技1术2维3护4专5员6:模7块8化9建10站11五12步13复14用15,效16率17提18升19三20倍2121字完美或者不用冒号直接空格:技术维护专员 模块化建站五步复用 效率提升三倍也可以nn注意要求“直接输出一个标题”,所以我们就输出一个标题我选择:技术维护专员:模块化建站五步复用,效率提升三倍
模块化VR建站:高效搭建,易于测试,reasoning_content:我们要求以功能测试工程师的口吻,写一个与技术、科技相关,关于“VR建站新思路:模块化设计引领高效搭建潮流”的标题需要简短精炼,30字以内直接输出标题,不要加说明nn功能测试工程师的口吻可能更注重测试、验证、效率、质量等角度比如“模块化VR建站:测试工程师的高效验证新方案”之类的但注意原标题是“VR建站新思路:模块化设计引领高效搭建潮流”,我们可以用测试视角重新表述nn例如:“模块化VR建站:高效搭建与快速测试新路径”或者“VR建站模块化:测试视角下的高效搭建革命”但要求短,30字内再简化:“模块化VR建站:高效搭建+易测试”或类似nn更直接:用“功能测试工程师”的视角说:“模块化设计让VR建站更易测试,高效搭建”但太长了nn考虑:“VR建站模块化:高效搭建与可测性双赢” 16字或者“模块化VR建站:效率与测试的完美结合” 18字或者“测试工程师推荐:模块化VR建站高效新招” 18字nn更贴合“新思路”:“模块化VR建站:高效搭建新思路(测试验证友好)”但超字数nn精简到30字内:比如“VR建站模块化:高效搭建,测试友好” 12字或者“模块化VR建站:让搭建更高效,测试更简单” 18字nn最终选择一个:考虑到口吻,用第一人称?或者直接陈述我觉得“模块化VR建站:高效搭建与测试验证新范式” 18字,但“范式”可能有点大更务实:“模块化VR建站:更快搭建,更易测试” 14字nn为了更像功能测试工程师的口吻,可以加入“实测”或“验证”例如:“模块化VR建站实测:高效搭建新思路” 16字nn我选择:“模块化VR建站:高效搭建+易测试的新思路” 18字或者更简洁:“VR建站模块化:高效搭建,易于测试” 14字nn最终输出一个标题注意不要加引号或其他符号直接输出文字
模块化思维驱动PHP建站高效落地,reasoning_content:我们要求以开发工程师的口吻,写一个与技术、科技相关,关于[模块化思维在PHP建站中的高效应用]的标题要求直接输出一个标题,不要加说明提示,简短精炼,30字以内nn需要体现模块化思维、PHP建站、高效应用开发工程师口吻,可以更技术化、专业nn可能的比如PHP模块化架构:提升建站效率的实战策略 但字数?数一下:PHP模块化架构:提升建站效率的实战策略 – 共17个字?PHP算两个?汉字+标点实际上PHP模块化架构:提升建站效率的实战策略 共18个字符(包括冒号)但PHP算3个字符,但通常标题中字母算一个30字以内没问题nn更直接:模块化思维:PHP建站高效部署之道 或 PHP模块化开发:让建站事半功倍nn注意要开发工程师口吻,可以带点专业自豪感nn推荐:模块化思维在PHP建站中的高效应用 本身已经是一个标题,但有点长?数一下:模块化思维在PHP建站中的高效应用 共16个汉字,没问题但不够口吻可以改成:我用模块化思维让PHP建站效率翻倍 共16字或者实战:模块化思维驱动PHP建站高效落地nn我倾向于:模块化思维:PHP建站效率提升的关键 共15字nn更简短:PHP模块化建站:高效开发新思路 13字nn最终选一个:直接用模块化思维在PHP建站中的高效应用 原题,但可能太普通nn考虑到要求与’技术、科技’相关,可以加科技感词汇,如赋能、驱动等nn模块化思维驱动PHP建站高效落地 14字nn确定输出:模块化思维驱动PHP建站高效落地
16 9 月 2026, 周三

PHP设计模式(八)装饰器模式Decorator实例详解【结构型】

副标题#e#

若你从事过面向对象开发,实现给一个类或对象增加行为,使用继承机制,这是所有面向对象语言的一个基本特性。如果已经存在的一个类缺少某些方法,或者须要给方法添加更多的功能(魅力),你也许会仅仅继承这个类来产生一个新类—这建立在额外的代码上。

通过继承一个现有类可以使得子类在拥有自身方法的同时还拥有父类的方法。但是这种方法是静态的,用户不能控制增加行为的方式和时机。如果  你希望改变一个已经初始化的对象的行为,你怎么办?或者,你希望继承许多类的行为,改怎么办?前一个,只能在于运行时完成,后者显然时可能的,但是可能会导致产生大量的不同的类—可怕的事情。

2. 问题

你如何组织你的代码使其可以容易的添加基本的或者一些很少用到的 特性,而不是直接不额外的代码写在你的类的内部?

3. 解决方案

装饰器模式: 动态地给一个对象添加一些额外的职责或者行为。就增加功能来说, Decorator模式相比生成子类更为灵活。

装饰器模式提供了改变子类的灵活方案。装饰器模式在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

当用于一组子类时,装饰器模式更加有用。如果你拥有一族子类(从一个父类派生而来),你需要在与子类独立使用情况下添加额外的特性,你可以使用装饰器模式,以避免代码重复和具体子类数量的增加。

4. 适用性

以下情况使用Decorator模式

1)• 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

2)• 处理那些可以撤消的职责。

3)• 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,

为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。

另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

5. 结构

uml如图:

PHP设计模式(八)装饰器模式Decorator实例详解【结构型】

6.构建模式的组成

抽象组件角色(Component):定义一个对象接口,以规范准备接受附加责任的对象,

即可以给这些对象动态地添加职责。

具体组件角色(ConcreteComponent) :被装饰者,定义一个将要被装饰增加功能的类。

可以给这个类的对象添加一些职责

抽象装饰器(Decorator):维持一个指向构件Component对象的实例,

并定义一个与抽象组件角色Component接口一致的接口

具体装饰器角色(ConcreteDecorator):向组件添加职责。

7. 效果

装饰模式的特点:

  (1) 装饰对象和真实对象有相同的接口。这样客户端对象就可以以和真实对象相同的方式和装饰对象交互。
  (2) 装饰对象包含一个真实对象的索引(reference)
  (3) 装饰对象接受所有的来自客户端的请求。它把这些请求转发给真实的对象。
  (4) 装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。

     Decorator模式至少有两个主要优点和两个缺点:

1) 比静态继承更灵活: 与对象的静态继承(多重继承)相比, Decorator模式提供了更加灵活的向对象添加职责的方式。可以用添加和分离的方法,用装饰在运行时刻增加和删除职责。相比之下,继承机制要求为每个添加的职责创建一个新的子类。这会产生许多新的类,并且会增加系统的复杂度。此外,为一个特定的Component类提供多个不同的 Decorator类,这就使得你可以对一些职责进行混合和匹配。使用Decorator模式可以很容易地重复添加一个特性。
2) 避免在层次结构高层的类有太多的特征 Decorator模式提供了一种“即用即付”的方法来添加职责。它并不试图在一个复杂的可定制的类中支持所有可预见的特征,相反,你可以定义一个简单的类,并且用 Decorator类给它逐渐地添加功能。可以从简单的部件组合出复杂的功能。这样,应用程序不必为不需要的特征付出代价。同时更易于不依赖于 Decorator所扩展(甚至是不可预知的扩展)的类而独立地定义新类型的 Decorator。扩展一个复杂类的时候,很可能会暴露与添加的职责无关的细节。
3) Decorator与它的Component不一样 Decorator是一个透明的包装。如果我们从对象标识的观点出发,一个被装饰了的组件与这个组件是有差别的,因此,使用装饰不应该依赖对象标识。
4) 有许多小对象 采用Decorator模式进行系统设计往往会产生许多看上去类似的小对象,这些对象仅仅在他们相互连接的方式上有所不同,而不是它们的类或是它们的属性值有所不同。尽管对于那些了解这些系统的人来说,很容易对它们进行定制,但是很难学习这些系统,排错也很困难。

8. 实现

使用《php设计模式》里面的例子。

看看以下例子,你可以更好的理解这种观点。考虑一个建立在组件概念上的“form”表单库,在那里你需要为每一个你想要表现的表单控制类型建立一个类。这种类图可以如下所示:

Select and TextInput类是组件类的子类。假如你想要增加一个“labeled”带标签的组件—一个输入表单告诉你要输入的内容。因为任何一个表单都可能需要被标记,你可能会象这样继承每一个具体的组件:

PHP设计模式(八)装饰器模式Decorator实例详解【结构型】

上面的类图看起来并不怎么坏,下面让我们再增加一些特性。表单验证阶段,你希望能够指出一个表单控制是否合法。你为非法控制使用的代码又一次继承其它组件,因此又需要产生大量的子类:

PHP设计模式(八)装饰器模式Decorator实例详解【结构型】

这个类看起来并不是太坏,所以让我们增加一些新的功能。在结构有效性确认中你需要指出结构是否是有效的。你需要让你检验有效性的代码也可以应用到其它部件,这样不用再更多的子类上进行有效性验证。

PHP设计模式(八)装饰器模式Decorator实例详解【结构型】

这里子类溢出并不是唯一的问题。想一想那些重复的代码,你需要重新设计你的整个类层次。有没有更好的方法!确实,装饰器模式是避免这种情况的好方法。

#p#副标题#e#

装饰器模式结构上类似与代理模式。一个装饰器对象保留有对对象的引用,而且忠实的重新建立被装饰对象的公共接口。装饰器也可以增加方法,扩展被装饰对象的接口,任意重载方法,甚至可以在脚本执行期间有条件的重载方法。

为了探究装饰器模式,让我们以前面讨论过的表单组件库为例,并且用装饰器模式而不是继承,实现“lable”和“invalidation”两个特性。

样本代码:

组件库包含哪些特性?

1.        容易创建表单元素

2.        将表单元素以html方式输出

3.        在每个元素上实现简单的验证

本例中,我们创建一个包含姓,名,邮件地址,输入项的表单。所有的区域都是必须的,而且E-mail必须看起来是有效的E—mail地址。用HTML语言表示,表单的代码象下面所示:

<form action=”formpage.php” method=”post”>
<b>First Name:</b> <input type=”text” name=”fname” value=””><br>
<b>Last Name:</b> <input type=”text” name=”lname” value=””><br>
<b>Email:</b> <input type=”text” name=”email” value=””><br>
<input type=”submit” value=”Submit”>
</form>

增加一些css样式后,表单渲染出来如下图所示:

PHP设计模式(八)装饰器模式Decorator实例详解【结构型】

我们使用装饰器代码:

<?php
/**
* 装饰器模式的组成:
* 抽象组件角色(Component):定义一个对象接口,以规范准备接受附加责任的对象,即可以给这些对象动态地添加职责。
* 具体组件角色(ConcreteComponent) :被装饰者,定义一个将要被装饰增加功能的类。可以给这个类的对象添加一些职责。
* 抽象装饰器(Decorator):维持一个指向构件Component对象的实例,并定义一个与抽象组件角色Component接口一致的接口。
* 具体装饰器角色(ConcreteDecorator): 向组件添加职责。
* @author guisu
* @version 1.0
*/
/**
* 抽象组件角色(Component)
*
*/
class ComponentWidget {
function paint() {
return $this->_asHtml();
}
}
/**
*
* 具体组件角色(ConcreteComponent):
* 让我们以一个基本的text输入组件开始。它(组件)必须要包含输入区域的名字(name)而且输入内容可以以HTML的方式渲染。
*
*/
class ConcreteComponentTextInput extends ComponentWidget {
protected $_name;
protected $_value;
function TextInput($name, $value=”) {
$this->_name = $name;
$this->_value = $value;
}
function _asHtml() {
return ‘<input type=”text” value=”‘.$this->_value.'”>’;
}
}
/**
* 抽象装饰器(Decorator):维持一个指向构件Component对象的实例,并定义一个与抽象组件角色Component接口一致的接口。
*
* 我们进入有能够统一增加(一些特性)能力的装饰器模式。
* 作为开始,我们建立一个普通的可以被扩展产生具体的特定装饰器的WidgetDecorator类。至少WidgetDecorator类应该能够在它的构造函数中接受一个组件,
* 并复制公共方法paint()
*
*/
class WidgetDecorator {
protected $_widget;
function __construct( &$widget) {
$this->_widget = $widget;
}
function paint() {
return $this->_widget->paint();
}
}
/**
* 具体装饰器角色(ConcreteDecorator):
* 为建立一个标签(lable),需要传入lable的内容,以及原始的组件
* 有标签的组件也需要复制paint()方法
*
*/
class ConcreteDecoratorLabeled extends WidgetDecorator {
protected $_label;
function __construct($label, &$widget) {
$this->_label = $label;
parent::__construct($widget);
}
function paint() {
return ‘<b>’.$this->_label.’:</b> ‘.$this->_widget->paint();
}
}
/**
* 实现
*
*/
class FormHandler {
function build(&$post) {
return array(
new ConcreteDecoratorLabeled(‘First Name’, new ConcreteComponentTextInput(‘fname’, $post->get(‘fname’)))
,new ConcreteDecoratorLabeled(‘Last Name’, new ConcreteComponentTextInput(‘lname’, $post->get(‘lname’)))
,new ConcreteDecoratorLabeled(‘Email’, new ConcreteComponentTextInput(’email’, $post->get(’email’)))
);
}
}
/**
* 通过$_post提交的数据
*/
class Post {
private $store = array();
function get($key) {
if (array_key_exists($key, $this->store))
return $this->store[$key];
}
function set($key, $val) {
$this->store[$key] = $val;
}
static function autoFill() {
$ret = new self();
foreach($_POST as $key => $value) {
$ret->set($key, $value);
}
return $ret;
}
}
?>

以创建一个php脚本使用FormHandler类来产生HTML表单:

#p#副标题#e##p#分页标题#e#

<form action=”formpage.php” method=”post”>
<?php
$post =& Post::autoFill();
$form = FormHandler::build($post);
foreach($form as $widget) {
echo $widget->paint(), “<br>\n”;
}
?>
<input type=”submit” value=”Submit”>
</form>

#p#副标题#e#

现在,你已经拥有了个提交给它自身并且能保持posted数据的表单处理(form handler) 类。
现在。我们继续为表单添加一些验证机制。方法是编辑另一个组件装饰器类来表达一个“invalid”状态并扩展FormHandler类增加一个validate()方法以处理组件示例数组。如果组件非法(“invalid”),我们通过一个“invalid”类将它包装在<span>元素中。

<?php
class Invalid extends WidgetDecorator {
function paint() {
return ‘<span>’.$this->widget->paint().'</span>’;
}
}

FormHandler新加方法validate:

#p#副标题#e#

/**
* 实现
*
*/
class FormHandler {
function build(&$post) {
return array(
new ConcreteDecoratorLabeled(‘First Name’, new ConcreteComponentTextInput(‘fname’, $post->get(‘fname’)))
,new ConcreteDecoratorLabeled(‘Last Name’, new ConcreteComponentTextInput(‘lname’, $post->get(‘lname’)))
,new ConcreteDecoratorLabeled(‘Email’, new ConcreteComponentTextInput(’email’, $post->get(’email’)))
);
}
function validate(&$form, &$post) {
$valid = true;
// first name required
if (!strlen($post->get(‘fname’))) {
$form[0] =& new Invalid($form[0]);
$valid = false;
}
// last name required
if (!strlen($post->get(‘lname’))) {
$form[1] =& new Invalid($form[1]);
$valid = false;}
// email has to look real
if (!preg_match(‘~\w+@(\w+\.)+\w+~’
,$post->get(’email’))) {
$form[2] =& new Invalid($form[2]);
$valid = false;
}
return $valid;
}
}

最后结果:

<html>
<head>
<title>Decorator Example</title>
<style type=”text/css”>
.invalid {color: red; }
.invalid input { background-color: red; color: yellow; }
#myform input { position: absolute; left: 110px; width: 250px; font-weight: bold;}
</style>
</head>
<body>
<form action=”<?php echo $_SERVER[“PHP_SELF”]; ?>” method=”post”>
<div>
<?php
$pos =& Post::autoFill();
$form = FormHandler::build($post);
if ($_POST) { FormHandler::validate($form, $post);
}
foreach($form as $widget) {
echo $widget->paint(), “<br>\n”;
}
?>
</div>
<input type=”submit” value=”Submit”>
</form>
</body>
</html>

9. 装饰器模式与其他相关模式

1)Adapter 模式:Decorator模式不同于Adapter模式,因为装饰仅改变对象的职责而
不改变它的接口;而适配器将给对象一个全新的接口。

2)Composite模式:可以将装饰视为一个退化的、仅有一个组件的组
合。然而,装饰仅给对象添加一些额外的职责—它的目的不在于对象聚集。

3)Strategy模式:用一个装饰你可以改变对象的外表;而Strategy模
式使得你可以改变对象的内核。这是改变对象的两种途径。

10.总结

1)使用装饰器设计模式设计类的目标是: 不必重写任何已有的功能性代码,而是对某个基于对象应用增量变化。 

2) 装饰器设计模式采用这样的构建方式: 在主代码流中应该能够直接插入一个或多个更改或“装饰”目标对象的装饰器,

同时不影响其他代码流。

3) Decorator模式采用对象组合而非继承的手法,实现了在运行时动态的扩展对象功能的能力,

而且可以根据需要扩展多个功能,避免了单独使用继承带来的“灵活性差”和“多子类衍生问题”。

同时它很好地符合面向对象设计原则中“优先使用对象组合而非继承”和“开放-封闭”原则。

也许装饰器模式最重要的一个方面是它的超过继承的能力。“问题”部分展现了一个使用继承的子类爆炸。

基于装饰器模式的解决方案,UML类图展现了这个简洁灵活的解决方案。

更多关于PHP相关内容感兴趣的读者可查看本站专题:《php面向对象程序设计入门教程》、《PHP数组(Array)操作技巧大全》、《PHP基本语法入门教程》、《PHP运算与运算符用法总结》、《php字符串(string)用法总结》、《php+mysql数据库操作入门教程》及《php常见数据库操作技巧汇总》

dawei

【声明】:北京站长网内容转载自互联网,其相关言论仅代表作者个人观点绝非权威,不代表本站立场。如您发现内容存在版权问题,请提交相关链接至邮箱:bqsm@foxmail.com,我们将及时予以处理。

您错过了

技术维护专员:模块化建站五步复用,效率提升三倍,reasoning_content:我们要求以技术维护专员的口吻,写一个与“技术、科技”相关,关于[模块化建站秘籍:五步轻松复用,效率提升300%]的标题注意:直接输出一个标题,不要加说明提示等信息;简短精炼,字数控制在30字以内nn口吻是技术维护专员,所以可以用一些技术术语或者口语化的技术表达标题要体现“模块化建站秘籍:五步轻松复用,效率提升300%”的核心内容需要简洁,30字以内nn可以考虑:技术维护专员教你模块化建站:五步复用,效率翻三倍但字数可能超?数一下:技术维护专员教你模块化建站:五步复用,效率翻三倍共22个字?标点不算吧?中文字数:技(1)术(2)维(3)护(4)专(5)员(6)教(7)你(8)模(9)块(10)化(11)建(12)站(13):五(14)步(15)复(16)用(17),效(18)率(19)翻(20)三(21)倍(22)22字可以但原词是“效率提升300%”,翻三倍就是300%或者可以更直接:模块化建站秘籍:五步复用,效率提升300%但缺少口吻可以加“技术维护专员说:”但可能太长nn更好的:技术维护专员:模块化建站五步复用,效率提升300%数一下:技(1)术(2)维(3)护(4)专(5)员(6):模(7)块(8)化(9)建(10)站(11)五(12)步(13)复(14)用(15),效(16)率(17)提(18)升(19)3(20)0(21)0(22)%(23)刚好23字注意标点符号不算字数?通常标题字数指汉字个数,标点一般不计但为了保险,可以不用标点或者去掉冒号:技术维护专员模块化建站五步复用效率提升300%数一下汉字:1技2术3维4护5专6员7模8块9化10建11站12五13步14复15用16效17率18提19升20300?300%是数字和百分号,算3个字符?通常汉字计数时数字和百分号算字符,但中文标题中常用也可以改成“三倍”:效率提升三倍这样更自然比如:技术维护专员:模块化建站五步复用,效率提升三倍汉字:技1术2维3护4专5员6:模7块8化9建10站11五12步13复14用15,效16率17提18升19三20倍2121字完美或者不用冒号直接空格:技术维护专员 模块化建站五步复用 效率提升三倍也可以nn注意要求“直接输出一个标题”,所以我们就输出一个标题我选择:技术维护专员:模块化建站五步复用,效率提升三倍