装饰器模式(Decorator Pattern)允许向一个现有对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
意图
动态的给一个对象添加额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。
解决问题
一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。
如何解决
将具体功能职责划分,同时继承装饰器模式
优点
装饰类和被装饰类可以独立发展,不会互相耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
缺点
多层装饰比较复杂
注意事项
可代替继承
C++实现
有一个手机,允许你为手机添加特性,比如增加挂件、屏幕贴膜等。一种灵活的设计方式是,将手机嵌入到另一对象中,由这个对象完成特性的添加,我们称这个嵌入的对象为装饰。这个装饰与它所装饰的组件接口一致,因此它对使用该组件的客户透明。
下面给出装饰器模式UML图:
在这种设计中,手机的装饰功能被独立出来,可以单独发展,进而简化了具体手机类的设计。
Code:
//装饰器模式
class Phone
{
public :
Phone()
{}
virtual ~Phone()
{}
virtual void showDecorate()
{}
};
class iPhone : public Phone //具体手机类
{
private:
string name;
public:
iPhone(string _name)
:name(_name)
{}
~iPhone()
{}
void showDecorate()
{
cout << name<<"的装饰"<< endl;
}
};
class NokiaPhone : public Phone
{
private:
string name;
public :
NokiaPhone(string _name)
:name(_name)
{}
~NokiaPhone()
{}
void showDecorate()
{
cout << name <<"的装饰"<< endl;
}
};
class DecoratorPhone :public Phone
{
private :
Phone* m_phone; //要装饰的手机
public:
DecoratorPhone(Phone *phone)
:m_phone(phone)
{}
virtual void showDecorate()
{
m_phone->showDecorate();
}
};
class DecoratePhoneA : public DecoratorPhone //具体的装饰A
{
public :
DecoratePhoneA(Phone* ph)
:DecoratorPhone(ph)
{}
void showDecorate()
{
DecoratorPhone::showDecorate();
AddDecorate();
}
private:
void AddDecorate()
{
cout <<"增加挂件" << endl;
}
};
class DecoratePhoneB : public DecoratorPhone
{
public:
DecoratePhoneB(Phone* ph)
:DecoratorPhone(ph)
{}
void showDecorate()
{
DecoratorPhone::showDecorate();
AddDecorate();
}
private:
void AddDecorate()
{
cout << "屏幕贴膜"<< endl;
}
};
客户端:
int test_Decorate() //装饰器模式
{
Phone* ph = new NokiaPhone("16300");
Phone *dpa = new DecoratePhoneA(ph);//增加挂件
Phone* dpb = new DecoratePhoneB(ph);//增加贴膜
ph->showDecorate();
delete ph;
delete dpa;
delete dpb;
system("pause");
return 0;
}
装饰模式提供了更加灵活的向对象添加职责的方式。可以用添加和分离的方法,用装饰在运行时刻增加和删除职责。装饰模式提供了一种“即用即付”的方法来添加职责。它并不试图在一个复杂的可定制的类中支持所有可预见的特征,相反,你可以定义一个简单的类,并且用装饰类给它逐渐地添加功能。可以从简单的部件组合出复杂的功能。[DP]
在本文的例子中,我们定义了两个具体的手机类,iPhone类和NokiaPhone类,通过单独的装饰类为它们添加特性,从而组合出复杂的功能。
与桥接模式的区别:
之前总结了C++设计模式——桥接模式;你会发现,二者都是为了防止过度的继承,从而造成子类泛滥的情况。那么二者之间的主要区别是什么呢?桥接模式的定义是将抽象化与实现化分离(用组合的方式而不是继承的方式),使得两者可以独立变化。可以减少派生类的增长。如果光从这一点来看的话,和装饰者差不多,但两者还是有一些比较重要的区别:
1.桥接模式中所说的分离,其实是指将结构与实现分离(当结构和实现有可能发生变化时)或属性与基于属性的行为进行分离;而装饰者只是对基于属性的行为进行封闭成独立的类,从而达到对其进行装饰,也就是扩展。比如:异常类和异常处理类之间就可以使用桥接模式来实现完成,而不能使用装饰模式来进行设计;如果对于异常的处理需要进行扩展时,我们又可以对异常处理类添加Decorator,从而添加处理的装饰,达到异常处理的扩展,这就是一个桥接模式与装饰模式的搭配;
2.桥接中的行为是横向的行为,行为彼此之间无关联,注意这里的行为之间是没有关联的,就比如异常和异常处理之间是没有行为关联的一样;而装饰者模式中的行为具有可叠加性,其表现出来的结果是一个整体,一个各个行为组合后的一个结果。
总结
装饰模式重点在装饰,对核心功能的装饰作用;将继承中对子类的扩展转化为功能类的组合,从而将需要对子类的扩展转嫁给用户去进行调用组合,用户如何组合由用户去决定。我在学习装饰模式时,就是重点分析了“装饰”这个词,我们都知道,装饰是在一个核心功能上添加一些附属功能,从而让核心功能发挥更大的作用,但是最终它的核心功能是不能丢失的。这就好比我们进行windows shell开发时,我们是对windows的这层壳进行了功能的装饰,从而实现了我们需要的一些装饰功能,但是最终的功能还是由windows shell去完成。这就好比,我们的装饰就是给核心功能添加了一层外衣,让它看起来更漂亮和完美。
参考:
http://www.jb51.net/article/55882.htm
http://blog.csdn.net/wuzhekai1985/article/details/6672614