1、概述

  装饰模式和适配器模式在通用类图上没有太多的相似点,差别比较大,但是它们的功能有相似的地方:都是包装作用,都是通过委托方式实现其功能。不同点是:装饰模式包装的是自己的兄弟类,隶属于同一个家族(相同接口或父类),适配器模式则修饰非血缘关系类,把一个非本家族的对象伪装成本家族的对象,注意是伪装,因此它的本质还是非相同接口的对象。

  大家都应该听过丑小鸭的故事吧,我们今天就用这两种模式分别讲述丑小鸭的故事。话说鸭妈妈有5个孩子,其中4个孩子都是黄白相间的颜色,而最小的那只也就是叫做丑小鸭的那只,是纯白色的,与兄弟姐妹不相同,在遭受了诸多的嘲讽和讥笑后,最终丑小鸭变成了一只美丽的天鹅。那我们如何用两种不同模式来描述这一故事呢?

2、装饰模式描述丑小鸭

2.1 类图

  用装饰模式来描述丑小鸭,首先就要肯定丑小鸭是一只天鹅,只是因为她小或者是鸭妈妈的无知才没有被认出是天鹅,经过一段时间后,它逐步变成一个漂亮、自信、优美的白天鹅。根据分析我们可以这样设计,先设计一个丑小鸭,然后根据时间先后来进行不同的美化处理,怎么美化呢?先长出漂亮的羽毛,然后逐步展现出异于鸭子的不同行为,如飞行,最终在具备了所有的行为后,它就成为一只纯粹的白天鹅了。类图比较简单,非常标准的装饰模式。

2.2 代码

2.2.1 天鹅接口

  我们按照故事的情节发展一步一步地实现程序。初期的时候,丑小鸭表现得很另类,叫声不同,外形不同,致使周围的亲戚、朋友都对她鄙视,那我们来建立这个过程,由于丑小鸭的本质就是一个天鹅,我们就先生成一个天鹅的接口。

class CISwan
{
public:
CISwan(){};
~CISwan(){}; //天鹅会飞
virtual void mvFly() = ;
//天鹅会叫
virtual void mvCry() = ;
//天鹅都有漂亮的外表
virtual void mvDesAppaearance() = ;
};

2.2.2 丑小鸭

  我们定义了天鹅的行为,都会飞行、会叫,并且可以描述她们漂亮的外表。丑小鸭是一只白天鹅,是"is-a"的关系,也就是需要实现这个接口了。

class CUglyDuckling : public CISwan
{
public:
CUglyDuckling(){};
~CUglyDuckling(){}; //丑小鸭的叫声
void mvCry() { cout << "叫声是克噜——克噜——克噜" << endl; }; //丑小鸭的外形
void mvDesAppaearance() { cout << "外形是脏兮兮的白色, 毛茸茸的大脑袋" << endl; } //丑小鸭还比较小,不能飞
void mvFly(){ cout << "不能飞行" << endl; };
};

2.2.3 抽象装饰类

  丑小鸭具备了天鹅的所有行为和属性,因为她本来就是一只白天鹅,只是因为她太小了还不能飞行,也不能照顾自己,所以丑丑的,在经过长时间的流浪生活后,丑小鸭长大了。终于有一天,她发现自己竟然变成了一只美丽的白天鹅,有着漂亮、洁白的羽毛,而且还可以飞行,这完全是一种升华行为。我们来看看她的行为(飞行)和属性(外形)是如何加强的。

class CDecorator : public CISwan
{
public:
CDecorator(CISwan *opSwan){ mopSwan = opSwan; };
~CDecorator(){}; virtual void mvCry() { mopSwan->mvCry(); }
virtual void mvFly() { mopSwan->mvFly(); }
virtual void mvDesAppaearance() { mopSwan->mvDesAppaearance(); } private:
CISwan *mopSwan;
};

2.2.4 外形装饰

  这是一个非常简单的代理模式。我们再来看丑小鸭是如何开始变得美丽的,变化是由外及里的,有了漂亮的外表才有内心的实质变化。

class CBeautifyAppearance : public CDecorator
{
public:
CBeautifyAppearance(CISwan *opSwan) : CDecorator(opSwan) {}; // 外表美化处理
void mvDesAppaearance() override { cout << "外表是纯白色的,非常惹人喜爱!" << endl; };
};

2.2.5 行为装饰

  丑小鸭最后发现自己还能飞行,这是一个行为突破,是对原有行为“不会飞行”的一种强化。

class CStrongBehavior : public CDecorator
{
public:
CStrongBehavior(CISwan *opSwan) : CDecorator(opSwan) {};
~CStrongBehavior(){}; // 会飞行了
void mvFly() override { cout << "会飞行了!" << endl; };
};

2.2.6 场景调用

  所有的故事元素我们都具备了,就等有人来讲故事了。

int main()
{
//很久很久以前, 这里有一个丑陋的小鸭子
cout << "===很久很久以前, 这里有一只丑陋的小鸭子===" << endl; CISwan *op_duck = new CUglyDuckling;
//展示一下小鸭子
op_duck->mvDesAppaearance();
op_duck->mvCry();
op_duck->mvFly(); cout << "===小鸭子终于发现自己是一只天鹅====" << endl;
//首先外形变化了
op_duck = new CBeautifyAppearance(op_duck);
//其次行为也发生了改变
op_duck = new CStrongBehavior(op_duck);
//虽然还是叫丑小鸭, 但是已经发生了很大变化
op_duck->mvDesAppaearance();
op_duck->mvCry();
op_duck->mvFly(); return ;
}

2.2.7 执行结果

  使用装饰模式描述丑小鸭蜕变的过程是如此简单,它关注了对象功能的强化,是对原始对象的行为和属性的修正和加强,把原本被人歧视、冷落的丑小鸭通过两次强化处理最终转变为受人喜爱、羡慕的白天鹅。

3、适配器模式实现丑小鸭

3.1 类图

  采用适配器模式实现丑小鸭变成白天鹅的过程要从鸭妈妈的角度来分析,鸭妈妈有5个孩子,它认为这5个孩子都是她的后代,都是鸭类,但是实际上是有一只(也就是丑小鸭)不是真正的鸭类,她是一只小白天鹅,因为太小,差别太细微,很难分辨,导致鸭妈妈认为她是一只鸭子,从鸭子的审美观来看,丑小鸭是丑陋的。通过分析,我们要做的就是要设计两个对象:鸭和天鹅,然后鸭妈妈把一只天鹅看成了小鸭子,最终时间到来的时候丑小鸭变成了白天鹅。

  类图非常简单,我们定义了两个接口:鸭类接口和天鹅类接口,然后建立了一个适配器UglyDuckling,把一只白天鹅封装成了小鸭子。

3.2 代码

3.2.1 鸭类接口

class CIDuck
{
public:
CIDuck(){};
~CIDuck(){}; //会叫
virtual void mvCry() = ; //鸭子的外形
virtual void mvDesAppearance() = ; //描述鸭子的其他行为
virtual void mvDesBehavior() = ;
};

  鸭类有3个行为,一个是鸭会叫,一个是外形描述,还有一个是综合性的其他行为描述,例如会游泳等。

3.2.2 小鸭子

class CDuckling : public CIDuck
{
public:
CDuckling(){};
~CDuckling(){}; void mvCry() { cout << "叫声是嘎——嘎——嘎" << endl; };
void mvDesAppearance() { cout << "外形是黄白相间,嘴长" << endl; }; // 鸭子的其他行为, 如游泳
void mvDesBehavior() { cout << "会游泳" << endl; };
};

3.2.3 白天鹅

  4只正宗的小鸭子形象已经清晰地定义出来了。鸭妈妈还有一个孩子,就是另类的丑小鸭,她实际是一只白天鹅。我们先定义出白天鹅。

class CISwan
{
public:
CISwan(){};
~CISwan(){}; //天鹅会飞
virtual void mvFly() = ;
//天鹅会叫
virtual void mvCry() = ;
//天鹅都有漂亮的外表
virtual void mvDesAppaearance() = ;
}; class CWhiteSwan : public CISwan
{
public:
CWhiteSwan(){};
~CWhiteSwan(){}; //白天鹅的叫声
void mvCry() { cout << "叫声是克噜——克噜——克噜" << endl; }; //白天鹅的外形
void mvDesAppaearance() { cout << "外形是纯白色,惹人喜爱" << endl; } //天鹅是能够飞行的
void mvFly(){ cout << "能够飞行" << endl; };
};

3.2.4 当成鸭子的白天鹅

  但是,鸭妈妈却不认为自己这个另类的孩子是白天鹅,它从自己的观点出发,认为她很丑陋,有碍自己的脸面,于是驱赶她——鸭妈妈把这只小天鹅误认为一只鸭。

class CUglyDuckling : public CWhiteSwan, public CIDuck
{
public:
CUglyDuckling(){};
~CUglyDuckling(){}; void mvCry() { CWhiteSwan::mvCry(); };
void mvDesAppearance() { CWhiteSwan::mvDesAppaearance(); };
void mvDesBehavior()
{
cout << "会游泳!" << endl;
CWhiteSwan::mvFly();
}
};

3.2.5 调用

  天鹅被看成了鸭子,有点暴殄天物的感觉。我们再来创建一个场景类来描述这一场景。

int main()
{
//鸭妈妈有5个孩子, 其中4个都是一个模样
cout << "===妈妈有五个孩子, 其中四个模样是这样的: ===" << endl;
CIDuck *op_duck = new CDuckling();
op_duck->mvCry();
op_duck->mvDesAppearance();
op_duck->mvDesBehavior();
cout << "===一只独特的小鸭子, 模样是这样的: ===" << endl;
CIDuck *op_ugly_duck = new CUglyDuckling;
op_ugly_duck->mvCry();
op_ugly_duck->mvDesAppearance();
op_ugly_duck->mvDesBehavior(); return ;
}

3.2.6 执行结果

  小天鹅被认为是一只丑陋的小鸭子...采用适配器模式讲述丑小鸭的故事,我们首先观察到的是鸭与天鹅的不同点,建立了不同的接口以实现不同的物种,然后在需要的时候(根据故事情节)把一个物种伪装成另外一个物种,实现不同物种的相同处理过程,这就是适配器模式的设计意图。  

4、总结

  我们用两个模式实现了丑小鸭的美丽蜕变。我们发现:这两个模式有较多的不同点。

  ● 意图不同

  装饰模式的意图是加强对象的功能,例子中就是把一个怯弱的小天鹅强化成了一个美丽、自信的白天鹅,它不改变类的行为和属性,只是增加(当然了,减弱类的功能也是可能存在的)功能,使美丽更加美丽,强壮更加强壮,安全更加安全;而适配器模式关注的则是转化,它的主要意图是两个不同对象之间的转化,它可以把一个天鹅转化为一个小鸭子看待,也可以把一只小鸭子看成是一只天鹅,它关注转换。

  ● 施与对象不同

  装饰模式装饰的对象必须是自己的同宗,也就是相同的接口或父类,只要在具有相同的属性和行为的情况下,才能比较行为是增加还是减弱;适配器模式则必须是两个不同的对象,因为它着重于转换,只有两个不同的对象才有转换的必要,如果是相同对象还转换什么?!

  ● 场景不同

  装饰模式在任何时候都可以使用,只要是想增强类的功能,而适配器模式则是一个补救模式,一般出现在系统成熟或已经构建完毕的项目中,作为一个紧急处理手段采用。

  ● 扩展性不同

  装饰模式很容易扩展!今天不用这个修饰,好,去掉;明天想再使用,好,加上。这都没有问题。而且装饰类可以继续扩展下去;但是适配器模式就不同了,它在两个不同对象之间架起了一座沟通的桥梁,建立容易,去掉就比较困难了,需要从系统整体考虑是否能够撤销。

【设计模式】 模式PK:装饰模式VS适配器模式的更多相关文章

  1. 【设计模式】 模式PK:代理模式VS装饰模式

    1.概述 对于两个模式,首先要说的是,装饰模式就是代理模式的一个特殊应用,两者的共同点是都具有相同的接口,不同点则是代理模式着重对代理过程的控制,而装饰模式则是对类的功能进行加强或减弱,它着重类的功能 ...

  2. Java IO设计模式(装饰模式与适配器模式)

    01. 装饰模式 1. 定义 Decorator装饰器,就是动态地给一个对象添加一些额外的职责,动态扩展,和下面继承(静态扩展)的比较.因此,装饰器模式具有如下的特征: 它必须持有一个被装饰的对象(作 ...

  3. 【设计模式】 模式PK:包装模式群PK

    1.概述 我们讲了这么多的设计模式,大家有没有发觉在很多的模式中有些角色是不干活的?它们只是充当黔首作用,你有问题,找我,但我不处理,我让其他人处理.最典型的就是代理模式了,代理角色接收请求然后传递到 ...

  4. 设计模式GOF23(结构型模式:代理模式,适配模式,桥接模式,组合模式,装饰模式,外观模式,享元模式)

    结构型模式: – 分类: • 适配器模式.代理模式.桥接模式.装饰模式.组合模式.外观模式.享元模式 – 核心作用:是从程序的结构上实现松耦合,从而可以扩大整体的类结构,用来解决更大的问题.   结构 ...

  5. 设计模式之结构类模式PK

    结构类模式包括: 适配器模式 桥梁模式 组合模式 装饰模式 门面模式 享元模式 代理模式 结构类模式着重于如何建立一个软件结构 为什么叫结构类模式呢? 因为他们都是通过组合类或对象产生更大结构以适应更 ...

  6. 设计模式:代理模式 vs 装饰模式

    参考文章:https://www.cnblogs.com/luoxn28/p/5535877.html 代理模式和装饰模式非常类似,甚至代码都类似. 二者最主要的区别是: 代理模式中,代理类对被代理的 ...

  7. 代理模式 vs 装饰模式

    代理模式和装饰模式有很大的相似性,二者的类图(几乎)是一样的.下面分别讲解代理模式和装饰模式. 1.代理模式 一般著名的跑步运动员都会有自己的代理人,如果想联系该运动员的比赛事宜,可以直接联系他的代理 ...

  8. 《Java设计模式》之装饰模式

    装饰模式(Decorator) 1.    装饰模式(Decorator)的定义:又名包装(Wrapper)模式.装饰模式以对client透明的方式扩展对象的功能,是继承关系的一个替代方案. 2.   ...

  9. 《JAVA设计模式》之装饰模式(Decorator)

    在阎宏博士的<JAVA与模式>一书中开头是这样描述装饰(Decorator)模式的: 装饰模式又名包装(Wrapper)模式.装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替 ...

随机推荐

  1. POJ 3675 Telescope(简单多边形和圆的面积交)

    Description Updog is watching a plane object with a telescope. The field of vision in the telescope ...

  2. HDU 1403 Longest Common Substring(后缀自动机——附讲解 or 后缀数组)

    Description Given two strings, you have to tell the length of the Longest Common Substring of them. ...

  3. 简单DP

      1.一只小蜜蜂   有一只经过训练的蜜蜂只能爬向右侧相邻的蜂房,不能反向爬行.请编程计算蜜蜂从蜂房a爬到蜂房b的可能路线数. 其中,蜂房的结构如下所示. Input输入数据的第一行是一个整数N,表 ...

  4. Thunder——基于NABCD评价“欢迎来怼”团队作品

    基于NABCD N——need需求 对于开设了软件工程课并且正在进行教学活动的老师和同学,除了在写作业时会打开电脑进行操作,平时我们更希望可以通过一些简单方便的方法来查看有关作业的内容,比如查看一下老 ...

  5. android仿美团客户端购买框悬浮特效

        实现步骤如下: 1,新建一个项目,新建一个MyScrollView继承自ScrollView   public class MyScrollView extends ScrollView { ...

  6. Java容器之List接口

    List 接口: 1. List 接口是 Collection 的子接口,实现 List 接口的容器类中的元素是有顺序的,而且可以重复: 2. List 容器中的元素都对应一个整数型的序号记载其在容器 ...

  7. .net下将exe改造为既能双击独立运行又能注册为windows服务

    最近项目中需要将一些业务的处理程序改造为windows服务,但是考虑到实际需求,也需要能够直接双击运行这些处理程序.首先第一步想到的就是原来的项目不变,只需要在加一个windows服务的项目就行.但是 ...

  8. PokeCats开发者日志(十一)

      现在是PokeCats游戏开发的第六十天的上午,易版权的状态变为了待收证,但愿不久就能送到了吧.

  9. Python 源码剖析(四)【LIST对象】

    四.LIST对象 1.PyListObject对象 2.PyListObject的创建与维护 3.PyListObject 对象缓冲池 4.Hack PyListObject 1.PyListObje ...

  10. 【题解】NOIP2015推销员

    ……普及组的题目都做不出来……(:´д`)ゞ……再这样下去要退役了啊…… 不过不管怎样感觉这题还是蛮好的,也要记录一下下~ 我们注意到数据的范围,n 是 1e5, 又有 1e5组询问,暴力大概是 \( ...