大话设计模式之(装饰器模式)

原创 2017年08月02日 17:35:00

导言:我曾经以为我可以用继承处理一切。后来我领教到运行时扩展,远比编译时期的继承威力大。装饰器模式可以给爱用继承的人一个全新的眼界。一旦你熟悉了装饰器模式,你将学会如何在运行的过程中给对象赋予新的指责和功能。


先不谈模式,如果现在要你开发一个可以给人搭配不同服饰的系统,不如类似QQ、网络游戏或论坛都有的Avatar系统,你怎么开发?
半小时后,小菜的第一版代码出炉。

代码结构图:

这里写图片描述

#include "stdafx.h"
#include <iostream>

using namespace std;

class Person
{
public:
    Person(string n){ name = n; }
    void wearTShirts(){ cout << "大T恤 "; }
    void wearBigTrouser(){ cout << "垮裤 "; }
    void wearSneakers(){ cout << "破球鞋 "; }
    void wearSuit(){ cout << "西装 "; }
    void wearTie(){ cout << "领带 "; }
    void wearLeatherShoes(){ cout << "皮鞋 "; }
    void show(){ cout << "装扮的" << name.c_str(); }
private:
    string name;
};

int _tmain(int argc, _TCHAR* argv[])
{
    Person* p = new Person("小菜");

    cout << "第一种装扮:" << endl;
    p->wearTShirts();
    p->wearBigTrouser();
    p->wearSneakers();
    p->show();

    cout << "第二种装扮:" << endl;
    p->wearSuit();
    p->wearTie();
    p->wearLeatherShoes();
    p->show();

    return 0;
}

功能是实现了,现在的问题是如果我要增加 “超人” 的装扮,你得如何做?“那就改改 ‘Person’ 类就行了”,小菜说完就反应过来了,“哦,不对,这就违背开放-封闭原则了。”
下面我们来说说装饰模式。装饰模式可以动态的给一个对象添加一些额外的职责。就增加功能来说,装饰模式比生成子类要更为灵活。
“啊,装饰这个词真好,无论衣服、鞋子、领带、披风其实都可以理解为对人的装饰,我们来看一下他的结构。”

结构图

这里写图片描述

Component是定义了一个对象接口,可以给这些对象动态的添加职责。ConcreteComponent是定义了一个具体的对象,也可以给这个对象添加一些职责。Decorator,装饰抽象类,继承了Component,从外类来扩展Component类的功能,但对于Component来说就无需知道Decorator的存在。至于ConcreteDecorator就是个具体的装饰对象,起到给Component添加职责的功能。

下面来看看具体的代码实现

Component类

class Component
{
public:
    virtual void operate() = 0;
};

ConcreteComponent类

class ConcreteComponent : public Component
{
public:
    virtual void operate() override
    {
        cout << "具体对象的操作" << endl;
    }
};

Decorate类

class Decorate : public Component
{
public:
    Decorate(Component* c){ comp = c; }

    virtual void operate() override
    {
        comp->operate();
    }
private:
    Component* comp = nullptr;
};

ConcreteDecorate类

class ConcreteDecorateA : public Decorate
{
public:
    ConcreteDecorateA (Component* c)
        : Decorate(c)
    {
        comp = c;
    }

    virtual void operate() override
    {
        Decorate::operate();
        addedState = "New state";
        cout << "具体装饰对象A的操作" << endl;
    }
private:
    string addedState;
};

class ConcreteDecorateB : public Decorate
{
public:
    ConcreteDecorateB(Component* c)
        : Decorate(c)
    {
        comp = c;
    }

    virtual void operate() override
    {
        Decorate::operate();
        addedBehavior();
        cout << "具体装饰对象B的操作" << endl;
    }
private:
    void addedBehavior()
    {
        cout << "addedBehavior" << endl;
    }
};

客户端代码


int _tmain(int argc, _TCHAR* argv[])
{
    ConcreteComponent* c = new ConcreteComponent();
    ConcreteDecorateA* d1 = new ConcreteDecorateA(c);
    ConcreteDecorateA* d2 = new ConcreteDecorateA(d1);

    d2->operate();

    return 0;
}

“我明白了,原来装饰模式是利用类的构造来对对象进行包装的。这样每个装饰对象的实现就和如何使用这个对象分离开了,每个装饰对象只关心自己的功能,不需要关心如何被添加到对象链当中。用刚才的例子来说,就是我们完全可以先穿外裤,再穿内裤,而不一定要先内后外。”
“既然你明白了,还不赶快把刚才的例子改成装饰模式的代码?”
“我还有个问题,刚才我写的例子中的 ‘人’ 类是Component还是ConcreteComponent呢?”
“哈,学习模式要善于变通,如果只有一个ConcreteComponent类而没有抽象的Component类,那么Decorator类可以是ConcreteComponent的一个子类。同样道理,如果只有一个ConcreteDecorator类,那么没必要建立一个单独的Decorator类,而可以把Decorator和ConcreteDecorator的责任合并成一个类。”
“啊,原来如此。在这里我们就没有必要有Component类了,直接让服饰类Decorator继承人类ConcreteComponent就可以了。”

二十分钟后,小菜的第三版代码出炉。

代码结构图:

这里写图片描述


Person类

class Person
{
public:
    Person(string n){ name = n; }
    virtual void show(){ cout << "装扮的" << name.c_str(); }
private:
    string name;
};

Finery(服饰类)


class Finery : public Person
{
public:
    void decorate(Person* p){ component = p; }
    virtual void show()
    {
        if (component)
        {
            component->show();
        }
    }
private:
    Person* component;
};

具体服饰类

class TShirts : public Finery
{
public:
    virtual void show()
    {
        cout << "大T恤 ";
        Finery::show();
    }
};

class BigTrouser : public Finery
{
public:
    virtual void show()
    {
        cout << "垮裤 ";
        Finery::show();
    }
};

//其余类似,省略

客户端代码


int _tmain(int argc, _TCHAR* argv[])
{
    Person* p = new Person("小菜");
    TShirts* ts = new TShirts();
    Suit* st = new Suit();
    BigTrouser* bt = new BigTrouser();

    //用大T恤装饰了一个光着的小菜
    ts->decorate(p);
    //用垮裤装饰了一个穿着大T恤的小菜
    bt->decorate(ts);
    //用西装装饰了一个穿着垮裤, 大T恤的小菜
    st->decorate(bt);
    bt->show();

    return 0;
}

总结:

装饰模式是为已有功能动态的添加更多功能的一种方式。

当系统需要新的功能时,我们原有的做法是向旧的代码加入新的代码。这些新的代码通常装饰了原有类的核心职责和主要行为,不如用西装来装饰小菜,但这种做法的主要问题在于,在主类中加入了新的字段,新的方法,新的逻辑,从而增加了主类的复杂度,同时也违背了开闭原则。

装饰模式提供了一个很好的解决方案,它把每个要装饰新增的功能放在单独的类中,并让这个类装饰他要包装的类。因此在需要执行特殊行为时,客户代码就可以运行时根据需要有选择,有顺寻的使用装饰功能装饰对象了。这样就把类的核心功能和装饰功能区分开了,而且可以去除相关类中重复的装饰逻辑。

版权声明:本文为博主原创文章,未经博主允许不得转载。

消息机制简单实现模块间解耦

消息机制一直是软件开发中减少模块之间耦合的标准方式,下面我们举一个简单的例子,看看是如何通过消息,减少类 A 和类 B之间的耦合度的。下面是传统的方法,实现 A 对 B 类的某个方法的调用,不使用消息...

使用python对cocos2dx的手游图片资源进行加密

使用python对cocos2dx的手游图片资源进行加密导言由于项目的需要,要对游戏的图片资源进行加密,目前比较常用的做法应该是使用TexturePacker的加密功能。但因为我们的整个打包流程都是p...

大话设计模式(Python版)--装饰器模式

第一版 #!/usr/bin/env python class Person: def __init__(self, name): self.__name = name ...

大话设计模式之装饰器模式

装饰器模式,顾名思义就是在一个原有的类的上增加额外的功能,前提是不能修改类的代码。其实为一个类增加功能,可以用继承来实现,但是这样会使得类的数量层爆炸式增长,每增加一个功能,都会通过继承生成一个新类。...

装饰器设计模式

  • 2017年02月09日 15:51
  • 178KB
  • 下载

慕课网----大话PHP设计模式 五(原型模式,装饰器模式,迭代器模式,代理模式)

16.原型模式 和工厂模式作用类似,都是用来创建对象 与工厂模式的实现不同,原型模式是先创建好一个原型对象,然后通过clone原型对象来创建新的对象,这样就免去了类创建时重复的初始化操作 原型模...

设计模式-装饰器模式

  • 2016年11月30日 21:29
  • 37KB
  • 下载

Java 装饰器设计模式

装饰器(Decorator)模式:      Decorator设计模式是典型的结构型模式(在GOF的那本模式的Bible中将模式分为:1.创建型模式;2.结构型模式;3.行为模式三种)。它的主要...
  • weiioy
  • weiioy
  • 2013年08月08日 14:46
  • 742
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:大话设计模式之(装饰器模式)
举报原因:
原因补充:

(最多只允许输入30个字)