什么是装饰器模式

作为一种结构型模式, 装饰器(Decorator)模式就是对一个已有结构增加"装饰".
适配器模式, 是为现在有结构增加的是一个适配器类,.将一个类的接口,转换成客户期望的另外一个接口.适配器让原本接口不兼容的类可以很好的合作.
装饰器模式是将一个对象包装起来以增强新的行为和责任.装饰器也称为包装器(类似于适配器)
有些设计设计模式包含一个抽象类,而且该抽象类还继承了另一个抽象类,这种设计模式为数不多,而装饰器就是其中之一.

什么时候使用装饰器模式

基本说来, 如果想为现有对象增加新功能而不想影响其他对象, 就可以使用装饰器模式.如果你好不容易为客户创建了一个网站格式, 主要组件的工作都很完美, 客户请求新功能时, 你肯定不希望推翻重来, 再重新创建网站. 例如, 假设你已经构建了客户原先请求的组件, 之后客户又有了新的需求, 希望在网站中包含视频功能. 你不用重写原先的组件, 只需要"装饰"现有组件, 为它们增加视频功能. 这样即可以保持原来的功能,还可以增加新功能.
有些项目可能有时需要装饰, 而有时不希望装饰, 这些项目体现了装饰器设计模式的另一个重要特性.假设你的基本网站开发模式可以满足大多数客户的要求. 不过, 胡些客户还希望有一些特定的功能来满足他们的需求. 并不是所有人都希望或需要这些额外的功能. 作为开发人员, 你希望你创建的网站能满足客户的业务目标. 所以需要提供"本地化"(customerization)特性, 即针对特定业务提供的特性. 利用装饰器模式, 不仅能提供核心功能, 还可以用客户要求的特有功能"装饰"这些核心功能.

简单的装饰器例子

一个web开发企业,计划建立一个基本网站,并提供一些增强功能. 不过,web开发人员知道, 尽管这个基本计划适用于大多数客户, 但客户以后很可能还希望进一步提升, 利用装饰器模式, 可以很容易地增加多个具体装饰器,另外由于你能选择要增加的装饰器, 所以企业不仅能控制功能, 还可以控制项目的成本 .

Component接口

Component参与者是一个接口, 在这里, 它是一个抽象类IComponent. 这个抽象类只有一个属性$site, 另外有两个抽象方法getSite()和getPrice().Component参与者具体为具体组件和Decorator参与者抽象类建立接口:
IComponent.php
<?php
abstract class IComponent
{protected $site;abstract public function getSite();abstract public function getPrice();
}

Decorator接口

这个例子中的装饰器接口可能会让你惊讶.这是一个抽象类,而且它还扩展了另一个抽象类! 这个类的作用就是维护组件接口(IComponent)的一个引用, 这是通过扩展IComponent完成的:
Decorator.php
<?php
abstract class Decorator extends IComponent
{/*任务是维护Component的引用继承getSite()和getPrice()因为仍然是抽象类,所以不需要实现父类任何一个抽象方法*/
}

Decorator类的主要作用就是维护组件接口的一个引用.
在所有的装饰器模式实现中, 你会发现,具体组件和装饰顺都有相同的接口. 它们的实现可能不同, 另外除了基本接口的属性和方法外, 组件和装饰器可能还有额外的属性和方法.

具体组件

这个例子中只有一个具体组件,它生成一个网站名, 另外生成一个基本网站报价:
BasicSite.php
<?php
class BasicSite extends IComponent
{public function __construct(){$this->site = "Basic Site";}public function getSite(){return $this->site;}public function getPrice(){return 1200;}
}

两个抽象方法都使用直接赋值来实现, 不过灵活性并不体现在如何改变设置的值.实际上, 要通过增加装饰器值来改变"Basic Site"值.

具体装饰器

这个例子中的具体装饰器与具体组件有相同的接口.实际上, 它们是从Decorator抽象类(而不是IComponent类)继承了这个接口. 不过,要记住, Decorator所做的就是继承IComponent接口.
Maintenance.php
<?php
class Maintenance extends Decorator
{public function __construct(IComponent $siteNow){$this->site = $siteNow;}public function getSite(){$format = "<br />  Maintenance";return $this->site->getSite() . $format;}public function getPrice(){return 950 + $this->site->getPrice();}
}

这个装饰器Maintenance在改变了site的值, 还有包装的具体组件价格上还会增加它自己 的价格. 另个两个具体装饰器与Maintenance装饰器也类似
Video.php
<?php
class Video extends Decorator
{public function __construct(IComponent $siteNow){$this->site = $siteNow;}public function getSite(){$format = "<br />  Video";return $this->site->getSite() . $format;}public function getPrice(){return 350 + $this->site->getPrice();}
}

DataBase.php
<?php
class DataBase extends Decorator
{public function __construct(IComponent $siteNow){$this->site = $siteNow;}public function getSite(){$format = "<br />  DataBase";return $this->site->getSite() . $format;}public function getPrice(){return 800 + $this->site->getPrice();}
}

测试这个应用时,可以看到,在基本的价格之上还会增加各个装饰器的价格.另外还能指定装饰器名的格式, 增加了两个空格,使之缩进
装饰器实现中最重要的元素之五就是构造函数, 要为构造函数提供一个组件类型. 由于这里只有一个具体组件, 所有装饰器的实例化都会使用这个组件. 使用多个组件时, 装饰器可以包装应用中的一部分或全部组件, 也可以不包装任何组件.

客户

Client类并不是这个设计模式的一部分, 但是正确使用Client类至关重要.每个装饰器在实例化时"包装"组件, 不过, 首先必须创建一个要包装的对象, 这里是BasicSite类实例
Client.php
<?php
function __autoload($class_name)
{include $class_name . '.php';
}
class Client
{private $basicSite;public function __construct(){$this->basicSite = new BasicSite();$this->basicSite = $this->WrapComponent($this->basicSite);$siteShow = $this->basicSite->getSite();$format = "<br />  <strong>Total= $";$price = $this->basicSite->getPrice();echo $siteShow . $format . $price . "</strong>";}private function WrapComponent(IComponent $component){$component = new Maintenance($component);$component = new Video($component);$component = new DataBase($component);return $component;}
}
$worker = new Client();

wrapComponent()方法检查传入的BasicSite实例, 以确保参数有正确的数据类型(IComponent), 然后分别实例化3个装饰器, 对该实例对象进行装饰.
Basic SiteMaintenanceVideoDataBaseTotal= $3300

适配器和装饰器模式都有另外一个名字"包装器"(wrapper)".
适配器可以"包装"一个对象, 创建一个与Adaptee兼容的接口, 而无须对它做任何修改.
装饰器也可以"包装"一个组件对象, 这样就能为这个已胡的组件增加职责, 而无须对它做任何修改.
下面的代码展示了Client如何将组件对象($component)包装在装饰器(Maintence)中:
$component = new Maintenance($component);

类似于"接口", 在计算机编程中用到"包装器"时, 不同的上下文会有不同的用法和含义. 一般来讲, 在设计模式中使用"包装器"是为了处理接口的不兼容, 或者希望为组件增加功能,包装器就表示用来减少不兼容性的策略.

转载于:https://www.cnblogs.com/chenqionghe/p/4782222.html

设计模式之: 装饰器模式相关推荐

  1. 设计模式学习----装饰器模式

    这两天本来是自在学习java collection Framework的Fail Fast底层机制,看到核心的部分时,突然意识到设计模式的问题,上大学到现在我还没有真正理解过设计模式的概念,于是用了大 ...

  2. 【设计模式】装饰器模式的使用

    问题来源 我们在进行软件系统设计的时候,有一些业务(如下图,一些通用的非功能性需求)是多个模块都需要的,是跨越模块的.把它们放到什么地方呢? 最简单的办法就是把这些通用模块的接口写好,让程序员在实现业 ...

  3. go设计模式之装饰器模式

    go设计模式之装饰器模式 再写这篇文章时,我已经看了很多其他人发表的类似文章,大概看了这么多吧. 亓斌的设计模式-装饰者模式(Go语言描述) jeanphorn的Golang设计模式之装饰模式 七八月 ...

  4. python中的装饰器、装饰器模式_python 设计模式之装饰器模式 Decorator Pattern

    #写在前面 已经有一个礼拜多没写博客了,因为沉醉在了<妙味>这部小说里,里面讲的是一个厨师苏秒的故事.现实中大部分人不会有她的天分.我喜欢她的性格:总是想着去解决问题,好像从来没有怨天尤人 ...

  5. python 设计模式之装饰器模式 Decorator Pattern

    #写在前面 已经有一个礼拜多没写博客了,因为沉醉在了<妙味>这部小说里,里面讲的是一个厨师苏秒的故事.现实中大部分人不会有她的天分.我喜欢她的性格:总是想着去解决问题,好像从来没有怨天尤人 ...

  6. 零基础学习设计模式之装饰器模式(配套视频)

    零基础学习设计模式之装饰器模式 定义 在不改变目标结构的情况下,动态的给对象增加功能 举例 如房子装修.相片加相框等,都是装饰器模式. 基本组件 抽象构件(Component)角色:定义一个抽象接口以 ...

  7. 详解设计模式:装饰器模式

    装饰器模式(Decorator Pattern)也称为包装模式(Wrapper Pattern),是 GoF 的 23 种设计模式中的一种结构型设计模式.装饰器模式 是指在不改变原有对象的基础之上,将 ...

  8. javascript设计模式之装饰器模式(结构型模式)

    javascript设计模式之装饰器模式 js的设计模式分为创建型模式,结构型模式和行为模式 结构模式描述了如何组合对象以提供新的功能. 装饰器模式是一种常见的结构型模式,我们可以以一个基础对象为基础 ...

  9. 设计模式之装饰器模式详解

    设计模式之装饰器模式详解 文章目录 设计模式之装饰器模式详解 一.什么是装饰器模式 二.装饰器模式的角色组成 三.装饰器模式通用写法示例 四.装饰器模式业务中的应用举例 五.装饰器模式优缺点 一.什么 ...

  10. 装饰者模式 php,PHP设计模式之装饰器模式

    装饰器设计模式 什么是装饰器模式 装饰器模式就是对一个已有的结构增加装饰.装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能.它是通过创建一个包装对象,也就是装饰来包裹真实的对象 ...

最新文章

  1. 上海大学建了一个“突发事件语料库”,包括地震、恐怖袭击等5大类
  2. css3 各种纸张贴纸效果
  3. access字段属性设置下拉列表_可嵌入您系统的.NET 报表控件ActiveReports:带状列表组件...
  4. CNN基础知识(2)
  5. 用C语言实现SGF格式围棋棋谱解析器
  6. 给定数字的b+树创建_在C ++中找到给定数字中的两个的下一个和上一个幂
  7. Linux内存管理:内存寻址之分段机制与分页机制
  8. 退休后你和原工作单位还有联系吗?
  9. 用Python爬了下知乎上的高颜值小姐姐后,我兴奋的睡不着觉!
  10. java 镶嵌创建线程_请教一个 Java 多线程嵌套使用的问题
  11. 解决办法:gtk_image_menu_item_set_image()菜单图标无法显示
  12. 安徽工业大学java实验报告_安徽工业大学java实验报告.doc
  13. Pano2VR制作全景漫游
  14. Error: DPI-1047: Cannot locate a 64-bit Oracle Client library: “问题
  15. 前端_http协议_html语言headbody基本介绍和用法
  16. 共享LPT口打印机打印时,注意事项
  17. 【面试积累】牛人的面试技巧分享
  18. python获取登录后的cookie_python爬虫使用cookie登录详解
  19. 垃圾填埋场渗滤液的主流处理方法
  20. 前端效果积累 |别具一格的3D酷炫轮播图效果收集

热门文章

  1. 如何定位和处理手机游戏内存泄露
  2. MySQL备份与恢复——基于OUTFILE /LOAD DATA 逻辑备份恢复
  3. Paxos一致性协议
  4. 零基础学Python-爬虫-2、scrapy框架(测试案例篇·技术点在后面文章内讲解)【测试将一篇小说的所有访问路径与标题存储到一个文件下】
  5. linux find 排除某目录或文件 执行
  6. 塔式服务器、机架式服务器、刀片服务器区别小结
  7. oracle数据库空间估算
  8. 云笔记项目-补充JS面向对象编程基础知识
  9. python 压缩 解压
  10. [Coderforces600E] Lomsat gelral