HeadFirst设计模式 之 C++实现(三):Decorator(装饰者模式)
装饰者模式是非常有意思的一种设计模式,你将可以在不改动不论什么底层代码的情况下。给你的(或别人的)对象赋予新的职责。
不是使用继承每回在编译时超类上改动代码,而是利用组合(composition)和托付(delegation)可以在执行时具有继承行为的效果。
代码应该如同晚霞中的莲花一样地关闭(免于改变),如同晨曦中的莲花一样地开放(可以扩展)。
这就是。设计原则之五:类应该对扩展开放,对改动关闭。
通常情况下。我们不会对代码的每一处设计都採用该原则,我们实在没有闲工夫把设计的每一个部分都这么设计(并且,就算做得到,也可能仅仅是一种浪费)。你须要把注意力集中在设计中最有可能改变的地方。然后应用开放-关闭原则。
装饰者模式,【动态地将责任附加到对象上】若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
当然。这并不代表我们在设计类的时候不採用继承。装饰者和被装饰者必须是一样的类型,也就是有共同的超类。这是相当关键的地方。在这里,我们利用继承达到“类型匹配”,而不是利用继承获得“行为”。假设依赖继承,那么类的行为仅仅能在编译时静态决定。
换句话说,行假设不是来自超类,就是子类覆盖后的版本号。
反之,利用组合。能够把装饰者混合着用……并且是在“执行时”。
以下我们来看星巴兹饮料的设计方案。四种饮料能够分别和不同数量不同种类的调料搭配起来销售给客户:
装饰者一般是用其它类似于工厂或生成器这种模式创建的。
组合和托付可用于在执行时动态地加上新的行为。
然后是我自己用C++实现的星巴兹饮料模型(在实现中,我增加了:在菜单上加上咖啡的容量大小供客户选择,因此也须要考虑调料依据咖啡容量收费),有疏漏的地方请不吝赐教:
// Decorator Patterm(装饰者设计模式)
#include <iostream>
#include <string>
enum SIZE{Tall_SIZE, GRANDE_SIZE, RENTI_SIZE};
using std::string; // 超类,ABC,抽象组件
class Beverage
{
public:
Beverage();
virtual ~Beverage();
int getSize(); // 在实现饮料搭配调料的基础上,加入的新功能
void setSize(int sizeOfBeverge); // 能够自主选择大中小杯。当然。价格也不一样哦~
virtual string & getDescription() = 0;
virtual float cost() = 0;
protected:
string m_description;
private:
SIZE m_size;
}; // 装饰类。抽象装饰
class CondimentDecorator : public Beverage
{
public:
virtual string & getDescription();
}; // 详细的咖啡。继承自超类。详细组件
class Espresso : public Beverage
{
public:
Espresso();
float cost();
}; class HouseBlend : public Beverage
{
public:
HouseBlend();
float cost();
};
// 另外两种饮料类(DarkRoast和Decaf)都是一样的 // 调料,详细装饰
class Mocha : public CondimentDecorator
{
private:
Beverage *m_beverage;
public:
Mocha(Beverage * beverage);
string & getDescription();
float cost();
}; class Whip : public CondimentDecorator
{
private:
Beverage *m_beverage;
public:
Whip(Beverage * beverage);
string & getDescription();
float cost();
};
DECORATOR—Mary过完轮到Sarly过生日。还是不要叫她自己挑了。不然这个月伙食费肯定玩完。拿出我去年在华山顶上照的照片,在背面写上“最好的的礼物。就是爱你的Fita”,再到街上礼品店买了个像框(卖礼品的MM也非常美丽哦)。再找隔壁搞美术设计的Mike设计了一个美丽的盒子装起来……我们都是Decorator,终于都在修饰我这个人呀,怎么样,看懂了吗?
装饰模式:装饰模式以对client透明的方式扩展对象的功能,是继承关系的一个替代方案,提供比继承很多其它的灵活性。动态给一个对象添加功能。这些功能能够再动态的撤消。添加由一些基本功能的排列组合而产生的很大量的功能。
// Decorator Patterm(装饰者设计模式) #include "DecoratorPattern.h" // 超类,ABC。抽象组件
Beverage::Beverage()
{
this->m_description = "Unknow Beverage";
m_size = RENTI_SIZE;
} Beverage::~Beverage()
{
} string & Beverage::getDescription()
{
return m_description;
} int Beverage::getSize()
{
return m_size;
} // 输入0 - Tall_SIZE小杯,输入1 - GRANDE_SIZE中杯
// 输入2 - RENTI_SIZE。输入others - 默认RENTI_SIZE大杯
void Beverage::setSize(int sizeOfBeverge)
{
switch(sizeOfBeverge)
{
case Tall_SIZE:
m_size = Tall_SIZE;
break;
case GRANDE_SIZE:
m_size = GRANDE_SIZE;
break;
case RENTI_SIZE:
default:
m_size = RENTI_SIZE;
break;
}
}
// CondimentDecorator没有什么好实现的,构造和析构都用默认 // 详细的咖啡,继承自超类,详细组件
Espresso::Espresso()
{
m_description = "Espresso Coffee";
} float Espresso::cost()
{
double allCost;
switch(getSize())
{
case Tall_SIZE:
allCost = 1.0;
break;
case GRANDE_SIZE:
allCost = 1.5;
break;
case RENTI_SIZE:
default:
allCost = 1.9;
break;
}
return allCost;
} HouseBlend::HouseBlend()
{
m_description = "HouseBlend Coffee";
} float HouseBlend::cost()
{
double allCost;
switch(getSize())
{
case Tall_SIZE:
allCost = .4;
break;
case GRANDE_SIZE:
allCost = .7;
break;
case RENTI_SIZE:
default:
allCost = .89;
break;
}
return allCost;
} // 调料,详细的装饰类
Mocha::Mocha(Beverage * beverage)
{
m_beverage = beverage;
} string & Mocha::getDescription()
{
return m_beverage->getDescription() + ", Mocha";
} float Mocha::cost()
{
double allcost = m_beverage->cost();
switch(m_beverage->getSize())
{
case Tall_SIZE:
allcost += .10;
break;
case GRANDE_SIZE:
allcost += .15;
break;
case RENTI_SIZE:
default:
allcost += .20;
break;
}
return allcost;
} Whip::Whip(Beverage * beverage)
{
m_beverage = beverage;
} string & Whip::getDescription()
{
return m_beverage->getDescription() + ", Whip";
} float Whip::cost()
{
double allcost = m_beverage->cost();
switch(m_beverage->getSize())
{
case Tall_SIZE:
allcost += .15;
break;
case GRANDE_SIZE:
allcost += .20;
break;
case RENTI_SIZE:
default:
allcost += .25;
break;
}
return allcost;
}
我们例如说,假设顾客想要双倍摩卡奶泡深焙咖啡中杯。实现例如以下(图表示的是摩卡和奶泡深焙咖啡的包括装饰结构):
<pre name="code" class="cpp">
int main()
{
// 双倍摩卡奶泡深焙咖啡中杯
Beverage * beverage1 = new Espresso();
beverage1->setSize(GRANDE_SIZE);
beverage1 = new Mocha(beverage1);
beverage1 = new Mocha(beverage1);
beverage1 = new Whip(beverage1); delete beverage1;
return 0;
}
我相信大家都实用过PS,并且都了解过PS中图层的原理。当我们P图片时候使用图层能够实现非常多效果。并且假设我们认为当中一个图层效果不好看我们能够直接删除,而不影响其它图层,我们每次P出来的照片都是一层层图层的叠加得到的。
这也是装饰者的一种可应用场景。
当然。装饰者模式也有缺点:
1、 装饰链不能过长。否则会影响效率。
2、仅仅在必要的时候使用装饰者模式,装饰者会导致设计中出现很多小对象,假设过度使用,会让程序变得非常复杂。添加系统维护难度。
转载请注明出处:http://blog.csdn.net/aall3210_tsingloon/article/details/28870771
HeadFirst设计模式 之 C++实现(三):Decorator(装饰者模式)的更多相关文章
- JAVA设计模式详解(三)----------装饰者模式
今天LZ带给大家的是装饰者模式,提起这个设计模式,LZ心里一阵激动,这是LZ学习JAVA以来接触的第一个设计模式,也许也是各位接触的第一个设计模式.记得当初老师在讲IO的时候就提到过它:“是你还有你, ...
- 设计模式(十):Decorator装饰者模式 -- 结构型模式
1. 概述 若你从事过面向对象开发,实现给一个类或对象增加行为,使用继承机制,这是所有面向对象语言的一个基本特性.如果已经存在的一个类缺少某些方法,或者须要给方法添加更多的功能(魅力),你也许会仅仅继 ...
- 设计模式PHP篇(三)————装饰器模式
简单的用php实现了装饰器模式: <?php /** *简单的装饰器模式 */ class PrintText { protected $decorators = []; public func ...
- 设计模式(三)装饰者模式Decorator
装饰者模式针对的问题是:对一个结构已经确定的类,在不改变该类的结构的情况下,动态增加一些功能. 一般来说,都是对一些已经写好的架构增加自己的功能,或者应对多种情况,增加功能. 我们还是来玩一句红警,首 ...
- Decorator装饰者模式(结构型模式)
1.需求 假设让我们去设计FCL中的Stream类,该类具有流类的基本功能,除了有各种不同类型的流外(如内存流.文件流.网络流等等),但是在不同的业务场景下,如处理银行业务,需要给相关的内存流进行加密 ...
- 设计模式(三)——装饰器模式(Decorator Pattern)
发现太过于刻意按照计划来写博客,有点不实际,刚好最近在一个网课上复习AOP的知识,讲到了装饰器模式和代理模式,顺便复习总结一下. 首先了解一下装饰器模式,从名字里面可以看出来,装饰器模式就类似于房子装 ...
- 12、Decorator 装饰器 模式 装饰起来美美哒 结构型设计模式
1.Decorator模式 装饰模式又名包装(Wrapper)模式.装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案. 装饰器模式(Decorator Pattern)允许向一个现 ...
- java设计模式—Decorator装饰者模式
一.装饰者模式 1.定义及作用 该模式以对客户端透明的方式扩展对象的功能. 2.涉及角色 抽象构件角色:定义一个抽象接口,来规范准备附加功能的类. 具体构件角色:将要被附加功能的类,实现抽象 ...
- [C++设计模式] decorator 装饰者模式
<head first>中 的样例:咖啡店有各种咖啡饮料,能够往咖啡里面加各种调料变成还有一种饮料.假设使用继承的方式来为每一种饮料设计一个类,代码的复杂度非常easy膨胀,并且会继承父类 ...
随机推荐
- SVN 删除所有目录下的“.svn”文件夹,让文件夹脱离SVN控制
SVN 删除所有目录下的“.svn”文件夹,将如下语句拷备到记事本,并保存为 *.reg,双击导入注册表,在文件夹右键中就多了一条“Delete SVN Folders”,点击就可以删处此目录下的所有 ...
- Python的深浅copy
27.简述Python的深浅拷贝以及应用场景? 深浅拷贝的原理 深浅拷贝用法来自copy模块. 导入模块:import copy 浅拷贝:copy.copy 深拷贝:copy.deepcopy 字面理 ...
- Linux 使用 yum 查看安装的软件包
Linux系统下yum命令查看安装了哪些软件包: $yum list installed //列出所有已安装的软件包 yum针对软件包操作常用命令: 1.使用YUM查找软件包 命令:yum searc ...
- 第五部分 linux 软件安装RPM SRPM与YUM
第五部分 linux 软件安装RPM SRPM与YUM 软件管理员简介 RPM与DPKG两大主流 rpm: redhat centos suse 命令:yum ...
- bootstrap 中dropmenu不起作用
今天在使用bootstrap发现dropmenu一直不起作用,代码是从官网拷贝过来. 网上查找可以用的页面进行一点点的去除分析,发现竟然是顺序反了导致的. 在使用dropmenu时需要引入jquery ...
- 【bzoj4319】cerc2008 Suffix reconstruction 贪心
题目描述 话说练习后缀数组时,小C 刷遍 poj 后缀数组题, 各类字符串题闻之丧胆.就在准备对敌方武将发出连环杀时,对方一记无中生有,又一招顺手牵羊,小C 程序中的原字符数组就被牵走了.幸运的是,小 ...
- 【bzoj2081】[Poi2010]Beads Hash
题目描述 Zxl有一次决定制造一条项链,她以非常便宜的价格买了一长条鲜艳的珊瑚珠子,她现在也有一个机器,能把这条珠子切成很多块(子串),每块有k(k>0)个珠子,如果这条珠子的长度不是k的倍数, ...
- 用Keepalived搭建双Nginx server集群,防止单点故障
综述: 浏览器访问虚拟IP: 192.168.1.57, 该虚拟IP被Keepalived接管,两个Keepalived进程分别运行在物理IP为192.168.1.56和192.168.1.59服务器 ...
- bzoj 3625小朋友和二叉树 多项式求逆+多项式开根 好题
题目大意 给定n种权值 给定m \(F_i表示权值和为i的二叉树个数\) 求\(F_1,F_2...F_m\) 分析 安利博客 \(F_d=F_L*F_R*C_{mid},L+mid+R=d\) \( ...
- 03深入理解C指针之---变量与内存
该系列文章源于<深入理解C指针>的阅读与理解,由于本人的见识和知识的欠缺可能有误,还望大家批评指教. C语言是一种编译型的语言,C源代码在编译成可执行文件后,经常以以下三种方式使用内存: ...