第11章 结构型模式—装饰模式

1. 装饰模式(Decorator Pattern)的定义

(1)动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式比生成子类更为灵活。

  ①装饰模式是为对象而不是类)添加功能的。

  ②用组合方式,而不是继承方式为对象添加功能。

(2)装饰模式的结构和说明

  ①Component:组件对象的接口,可以给这些对象动态地添加职责。

  ②ConcreteComponent:具体的组件对象,实现组件对象接口,通常就是被装饰器装饰的原始对象,也就是可以给这个对象添加职责。

  ③Decorator:所有装饰器的抽象父类,需要定义一个与组件接口一致的接口,并持有一个Component对象的指针,其实就是持有一个被装饰的对象。之所以从Decorator继承而来,除了与被装饰对象接口相同,还是有个原因是Decorator本身也可以被进一步的装饰,形成多层的装饰。注意,装饰后仍然是一个Component对象,而且其功能更为复杂。

  ④ConcreteDecorator:实际的装饰器对象,实现具体要向被装饰对象添加的功能。

(3)思考装饰模式

  ①装饰模式的本质动态组合。动态是手段,组合才是目的。通过对象组合(而不是继承)来实现为被装饰对象透明的增加功能,而且也可以控制功能的访问。

  ②装饰模式的动机:由于继承为类型引入的静态特质,使得通过继承扩展方式缺乏灵活性,并且随着子类的增多,会导致子类的膨胀。而装饰模式可以根据需要来动态地使“对象功能扩展”,避免子类膨胀问题

  ③装饰器:不仅仅可以给被装饰对象增加功能,还可以根据需要选择是否调用被装饰对象的功能。如果不调用,那就变成完全重新实现,相当于动态修改了被装饰对象的功能。同时装饰器一定要实现和组件类一致的接口,保证它们是同一个类型,并具有同一个外观,这样组合完成的装饰才能够递归调用下去

2. 装饰模式的优缺点

(1)优点

  ①比继承更灵活:继承是静态的,而装饰模式把功能分离到每个装饰器,然后通过组合方式,在运行时动态地组合功能。

  ②更容易复用功能:一般一个装饰器只实现一个功能,使实现装饰器变得简单,更重要的是这样有利于装饰器功能的复用,可以给一个对象增加多个不同装饰器,也可以用一个装饰器不同的对象,从而实现复用装饰器的功能。

  ③简化高层定义:通过组合装饰器的方式,在进行高层定义的时候,不用把所有功能都定义出来,而是定义最基本的就可以了,在需要的时候,组合相应的装饰器来完成所需的功能。

(2)缺点

  ①会产生很多细粒度的对象

  ②多层的装饰是比较复杂的,应尽量减少装饰类的数据,以便降低系统的复杂度。

3. 使用场景

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

(2)不适合使用子类来进行扩展时,可以考虑使用装饰模式。因为装饰模式是使用“对象组合”的方式。所谓不适合用子类扩展的方式,比如扩展功能需要的子类太多,造成子类数目呈爆炸性增长。

(3)需要为一批兄弟类进行改装或加装功能。可以选用装饰模式。

【编程实验】在显示每个Window前追加显示某个logo的功能。

//结构型模式:装饰模式
//场景:在显示每个Window前追加显示某个logo的功能。

#include <iostream>

using namespace std;

//************************抽象组件类******************
class BaseWin  //Component
{
public:
   virtual void show() = 0; //显示
};

//***********************具体组件角色*******************
//PrintDialog
class PrintDialog : public BaseWin
{
public:
    void show()
    {
        cout << "PrintDialog" << endl;
    }
};

//WinConfig:配置窗口
class WinConfig : public BaseWin
{
public:
    void show()
    {
        cout << "WinConfig" << endl;
    }
};

//MainWin:主窗口
class MainWin : public BaseWin
{
public:
    void show()
    {
        cout << "MainWin" << endl;
    }
};

//*****************************装饰器类**********************
class DecoratorWin : public BaseWin //继承,如此装饰后仍是BaseWin类
{
private:
    BaseWin* mWin; //持有一个被装饰对象的指针
public:
    DecoratorWin(BaseWin* Win){this->mWin = Win;}
    void show()
    {
        mWin->show();
    }
};

//具体的装饰器
class LogWin : public DecoratorWin
{
private:
    void displayLogo() {cout << "LogoWin Showing..." << endl;}

public:
    LogWin(BaseWin* win) : DecoratorWin(win){}

    void show()
    {
        displayLogo(); //增加功能,在原窗口显示之前,先显示Logo窗口
        DecoratorWin::show();
    }
};

int main()
{
    //客户端调用

    //显示主窗口前先显示Logo窗口
    BaseWin* mainWin= new MainWin();
    BaseWin* logo = new LogWin(mainWin);
    logo->show();

    //显示打印对话框前先显示Logo窗口
    BaseWin* printDlg = new PrintDialog();
    BaseWin* logo2 = new LogWin(printDlg);
    logo2->show();

    delete mainWin;
    delete logo;
    delete printDlg;
    delete logo2;

    return 0;
}

4. 相关模式

(1)装饰模式与策略模式

  ①策略模式也可以实现动态地改变对象的功能,但是策略模式只是一层选择,也就是根据策略选择一下具体的实现类而己。而装饰模式不是一层,而是递归调用,无数层都可以。

  ②策略模式改变的是原始对象的功能,其改变的是对象的内核。而装饰器可以看作是一个对象的外壳,改变的是经过前一个装饰器装饰后的对象,可改变对象的行为。

  ③Decorator模式仅从外部改变对象,因此对象无需对它的装饰有任何了解;也就是装饰对象该对象来说是透明的。但策略模式,Component组件本身知道可能进行哪些扩充,因此它必须引用并维护相应的策略。

  ④策略的方法可能需要修改Component组件以适应新的扩充,另一方面,一个策略可以有自己特定的接口,而装饰的接口则必须与组件接口一致。

(2)装饰模式与模板方法模式

  两者的功能有点相似,模板方法主要应用在算法骨架固定的情况。如果是一个相对动态的算法,可以使用装饰模式,因为用装饰器组装时,其实也相当于一个调用算法的步骤,相当于一个动态的算法骨架。

时间: 2024-10-05 15:07:48

第11章 结构型模式—装饰模式的相关文章

结构型模式 装饰模式

结构型模式 装饰模式 适用于:  装饰者模式(Decorator Pattern)动态的给一个对象添加一些额外的职责.就增加功能来说,此模式比生成子类更为灵活. /** * 结构型模式 装饰模式 * 装饰( Decorator )模式又叫做包装模式. * 通过一种对客户端透明的方式来扩展对象的功能,是继承关系的一个替换方案. * 装饰模式就是把要添加的附加功能分别放在单独的类中,并让这个类包含它要装饰的对象,当需要执行时,客户端就可以有选择地.按顺序地使用装饰功能包装对象. * */ #defi

第14章 结构型模式—代理模式

1. 代理模式(Proxy Pattern)的定义 (1)为其他对象提供一种代理以控制对这个对象的访问 ①代理模式在客户和被客户访问的对象之间,引入了一定程度的间接性,客户是直接使用代理,让代理来与被访问的对象进行交互. ②这种附加的间接性增加了灵活性和不同的用途. (2)代理模式的结构和说明 ①Proxy:代理对象,通常实现与具体的目标对象一样的接口,这样就可以使用代理来代替具体的目标对象. A.保存一个指向具体目标对象的指针,可以在需要的时候调用具体的目标对象,若RealSubject和Su

第9章 结构型模式—桥接模式

1. 桥接模式(Bridge Pattern)的定义 (1)将抽象部分与它的实现部分分离,使它们都可以独立地变化 ①一般的“抽象”与“实现”是指父子类的继承关系.但这里,GoF所谓的“抽象”是如果引起一个类变化是多维度的因素(设为2维),就将其他变化因素抽象成一个接口,在“Abstraction类”中只留这个接口,然后通过对象组合(而不是继承)的方式去依赖这个接口.而“实现”是指在让另一个“Implementor类”的子类去实现接口(第2维度的变化). ② “Abstraction类”和“Imp

第12章 结构型模式—外观模式

1. 外观(门面)模式(Facade Pattern)的定义 (1)为子系统中的一组接口提供一个一致的界面,Façade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用. ①这里说的界面是指从一个组件外部来看这个组件,能够看到什么,也就是外观.如从一个类外部看这个类,那么这个类的public方法或接口就是他的外观. ②这里所说的“接口”是指外部和内部交互的一个通道(方法),可以是类的方法,也可以是interface的方法. (2)外观模式的结构和说明 ①Façade:定义子系统的多个模

第13章 结构型模式—享元模式

1. 享元模式(Flyweight Pattern)的定义 (1)运用共享技术高效地支持大量细粒度的对象 ①对象内部状态:数据不变且重复出现,这部分不会随环境变化而改变,是可以共享的. ②对象外部状态:数据是变化的,会随环境变化而改变,是不可以共享的. ③所谓的享元,就是把内部状态的数据分离出来共享,通过共享享元对象,可以减少对内存的占用.把外部状态分离出来,放到外部,让应用程序在使用的时候进行维护,并在需要的时候传递给享元对象使用. ④享元模式真正缓存和共享的是享元的内部状态,而外部状态是不被

java设计模式--结构型模式--装饰模式

1 装饰模式 2 概述 3 动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator模式相比生成子类更为灵活. 4 5 6 适用性 7 1.在不影响其他对象的情况下,以动态.透明的方式给单个对象添加职责. 8 9 2.处理那些可以撤消的职责. 10 11 3.当不能采用生成子类的方法进行扩充时. 12 参与者 13 1.Component 14 定义一个对象接口,可以给这些对象动态地添加职责. 15 16 2.ConcreteComponent 17 定义一个对象,可以给这个对象添

10 结构型模式-----装饰模式

模式动机(Decorator Pattern):我们在给一个类进行功能扩展时,总是通过继承或者复合关系,使得一个类具有其他相关类型的功能,继承本身属于静态关联,派生类比较臃肿,使用者也不能控制增加功能的方式.而使用复合机制,即将一个类的对象作为另一个类的成员,我们可以决定什么时候调用哪种功能,非常方便,这就是装饰模式,即给一个现有的类进行装饰,使其具有我们希望的功能. 模式结构图: 模式代码: bt_装饰模式.h: 1 #ifndef DP_H 2 #define DP_H 3 #include

设计模式--结构型模式--装饰模式

装饰者模式: 我们可以通过继承和组合的方式来给一个对象添加行为,虽然使用继承能够很好拥有父类的行为,但是它存在几个缺陷: 一.对象之间的关系复杂的话,系统变得复杂不利于维护. 二.容易产生“类爆炸”现象. 三.是静态的.在这里我们可以通过使用装饰者模式来解决这个问题. 装饰者模式,动态地将责任附加到对象上.若要扩展功能,装饰者提供了比继承更加有弹性的替代方案.虽然装饰者模式能够动态将责任附加到对象上,但是他会产生许多的细小对象,增加了系统的复杂度. uml类图如下: 装饰者Decorator与被

第27章 结构型模式大PK

27.1 代理模式 VS 装饰模式 27.1.1 代理模式 (1)场景:客人找运动员代理要求安排运动员参加比赛 (2)说明:代理人有控制权,可以拒绝客人的要求,也可以答应安排,甚至自己下去跑(因为有些运动员本身就作自己的代理) [编程实验]找代理安排运动员比赛 //创建型模式大PK——代理模式和装饰模式 //实例:找代理安排运动员比赛 #include <iostream> #include <ctime> using namespace std; //抽象运动员 class IR