您的位置:首页 > 编程语言 > Go语言

读GOF设计模式杂记之 Decorator

2008-08-02 21:18 141 查看
模式名:Decorator

意图:“动态地” 给一个“对象” 添加一些额外的职责。

这句话是相对于“静态地” 给一个类添加功能说的。当需要给一个对象增加功能的时候可以有以下两种选择:

(1) 一种选择是在这个对象的类上添加额外的功能代码。

缺点: 第一种方式会造成所有的这个类的对象其行为都发生改变。

(2) 第二种选择是为这个类派生一个子类用来增加其功能。

缺点:
第二种方式利用了面向对象思想的继承和多态特性,它可以在不改变其他对象的前提下产生一个派生类型来增加功能。不过这样做有一点不足就是会造成类数量的爆
炸。例如有100动物的类,他们有共同的基类“动物”。其中的30种动物成长到一定年龄就会有飞翔的功能,需要给这30种动物增加飞翔的功能。如果利用第
二种方式就会增加30个派生类来表示那些成长到一定年龄的会飞翔的动物。而且如果我想找一种飞翔的动物来送信那么就需要静态的(对于静态语言,如果是动态
语言就没有这个问题了)选择好那种动物。

用法:这时我们就可以使用Decorator模式来解决我们的问题。

我们还以刚才的那个例子来说明问题。我们从“动物”基类派生一个flyAmnimal,这个类包含一个指向其他动物的指针,并把基类的接口
(virtual 接口)都映射到所指向的动物身上。另外为所指向的动物增加一个飞翔功能。这个flyAnimal就是一个
decorator模式的类。

优点:代码复用,我们不用在为不同的类定义多个派生类。避免生成多个派生类来重复添加某一特征。

更为灵活,可以动态指定使用那种飞翔的动物来送信。

缺点:代码结构更为复杂,系统更难理解,对于对系统不是很了解的人来说,很难为其增加功能。排错也更困难。

当所修饰的对象非常大的时候,decorator的代价就会很高。可以考虑使用stategy模式替代。

注意: 接口一致性,修饰类和被修饰类必须要相同的接口,也就是有共同的基类。

可以省略抽象的Decorator。仅需要增加一个职责的时候Decorator可以只有一个而不是一个Decorator树。

和Strategy模式的比较:

Decorator可以看作是改变一个对象的外壳,不改变其已有的内核。只是给对象增加一些功能。Decorator对象在组件对象的外部。

Strategy模式却是改变对象的内核,给对象一组可选的内核功能。Strategy的对象在组件对象的内部。

和composite模式的比较:

Decorator可以看作一个退化了的,只有一个组建的composite,同时还可以看作一个增强了功能的composite。它弱化了composite的聚集对象的功能,却强化了唯一一个component的能力。

一个例子:

/*

*file name:animal.cpp

*description:一个简单的decorator模式的例子

* author: yingjie

* */

#include <iostream>

using namespace std;

/*

* 定义animal基类

* */

class animal

{

public:

virtual string name() const = 0;

virtual void run()const {cout << "I am runing!" << endl;}

virtual ~animal(){}

};

/*

*animal 派生的eagle

* */

class eagle:public animal

{

string name()const {return string("eagle"); }

};

/*

*animal 派生的dove

* */

class dove:public animal

{

string name()const {return string("dove"); }

};

/*

*animal 派生的birdmen

* */

class birdmen:public animal

{

string name()const {return string("birdmen"); }

};

/*

*最关键的decorator类,它和eagle,dove一样继承自animal,它拥有一个指向animal的指针,并且把基类所有的virtual函数映射到所指向的animal的实现中。然后添加自己修饰函数

* */

class flyAnimal:public animal

{

public:

flyAnimal():p(0){}

flyAnimal(animal * ptr):p(ptr){}

void setAnimal(animal * ptr){delete p;p = ptr;}

//把基类的virtual函数“全部”映射到所修饰的对象的实现上。

string name()const

{

if (p) return p->name();

return "no decorated animal!";

}

void run()const{if (p) p->run();}

void fly()const{if (p) cout << "I am flying!" << endl;} //添加的修饰函数

~flyAnimal(){delete p;}

private:

animal *p;

};

/*

*找一个信使去送信

* */

void sendMail(const flyAnimal & sender)

{

cout << "I am " << sender.name() << endl;

sender.run();

sender.fly();

}

int main()

{

flyAnimal sender(new eagle); //用eagle做信使

sendMail(sender);

sender.setAnimal(new dove); //动态改变信使

sendMail(sender);

sender.setAnimal(new birdmen); //会飞的不一定是天使,还有鸟人

sendMail(sender);

}

运行结果:

I am eagle

I am runing!

I am flying!

I am dove

I am runing!

I am flying!

I am birdmen

I am runing!

I am flying!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: