//说些废话
一开始当然是照旧说些废话,对于装饰模式嘛,我觉得理解是十分容易理解的,因为就想一个人穿衣服,你就给这个人装饰上衣服就行了。
但是吧,我觉得装饰类的划分有点难理解。
说是说在不影响其他对象的情况下,动态、透明地给单个对象增加职责,但我还是很难想到实际项目用到装饰模式的情况,意味着你得预料到有装饰成分在。
//部分资料来源
1.C++设计模式:http://www.jellythink.com/archives/171
2.程杰的大话设计模式
//适用场合
1.在不影响其他对象的情况下,以动态的,透明的方式给单个对象增加职责
2.处理那些可以撤销的职责
3.当不能采用生成子类的方法进行扩充时。
一种情况是,可能存在大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。
另一种情况是可能是因为类定义被隐藏,或类定义不能用于生成子类。
//正文
两种实现,不过其实都是一个意思,只是看你喜欢继承构造函数让类看起来紧凑一点 还是 喜欢简单的不写构造函数
第一种:
<pre name="code" class="cpp">class Component
{
public:
virtual void Operation()
{
cout<<"plane"<<endl;
}
};
class ConcreteComponent : public Component
{
public:
void Operation()
{
cout<<"I am the ConcreteComponent Class"<<endl;
}
};
//DecoratorA这类,继承构造函数的方法
// start
class DecoratorA : public Component
{
public:
DecoratorA(Component *pComponent) : DecoComponent(pComponent){}
void Operation()
{
if(DecoComponent != nullptr)
{
DecoComponent->Operation();
}
}
private:
Component *DecoComponent;
};
class ConcreteDectoratorA : public DecoratorA
{
public:
ConcreteDectoratorA(Component *DecoComponent) : DecoratorA(DecoComponent){}
void Operation()
{
cout<<"blue ";
DecoratorA::Operation();
}
};
class ConcreteDectoratorB : public DecoratorA
{
public:
ConcreteDectoratorB(Component *DecoComponent) : DecoratorA(DecoComponent){}
void Operation()
{
cout<<"grey ";
DecoratorA::Operation();
}
};
// end A
第二种:
<pre name="code" class="cpp">class Component
{
public:
virtual void Operation()
{
cout<<"plane"<<endl;
}
};
class ConcreteComponent : public Component
{
public:
void Operation()
{
cout<<"I am the ConcreteComponent Class"<<endl;
}
};
//DecoratorB这类,直接用Decorate方法对Component进行装饰
// start
class DecoratorB : public Component
{
public:
void Decorate(Component *pComponent)
{
DecoComponent2 = pComponent;
}
void Operation()
{
if(DecoComponent2 != nullptr)
{
DecoComponent2->Operation();
}
}
private:
Component *DecoComponent2;
};
class ConcreteDectorator2A : public DecoratorB
{
public:
void Operation()
{
cout<<"can-run ";
DecoratorB::Operation();
}
};
class ConcreteDectorator2B : public DecoratorB
{
public:
void Operation()
{
cout<<"can-fly ";
DecoratorB::Operation();
}
};
// end B
然后看看主函数吧:
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Component *plane = new Component;
//DecorateA部分
DecoratorA *concreteA = new ConcreteDectoratorA(plane);
DecoratorA *concreteB = new ConcreteDectoratorB(concreteA);
concreteB->Operation();
//DecorateB部分
DecoratorB *concrete2A = new ConcreteDectorator2A;
DecoratorB *concrete2B = new ConcreteDectorator2B;
concrete2A->Decorate(plane);
concrete2B->Decorate(concrete2A);
concrete2B->Operation();
return a.exec();
}
首先来看看装饰模式的定义:
装饰模式(Decorator),动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。[DP]
联系上这段来理解:
当不能采用生成子类的方法进行扩充时。
一种情况是,可能存在大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。
另一种情况是可能是因为类定义被隐藏,或类定义不能用于生成子类。
其实就是说,你一个Parent类,封装好了,但是你要对其进行功能的添加或者修改操作
然后“不暴露定义”也要“保持开放-封闭原则”,也就是说,你不去修改Parent类,这种情况下,通常我们会想到:继承
(注意一下,虽然开放-封闭原则是批准在早期针对新增需求进行修改类的操作,但是当我们这些“新加入的东西仅仅是为了满足一些只在某种特定情况下才会执行的特殊行为的需要”时,我们就不要在Parent类里面修改或新增了,为什么呢?因为这只会增加了类的复杂度,而不是使类更加完整)
继承是可以的,不过当我们出现下面的情况时,继承会怎样呢?
1.需要把所需要的功能按正确的顺序串联起来进行控制
2.在不影响其他对象的情况下,以动态的、透明的方式给单个对象增加职责
3.处理那些可以撤销的职责
我们就会感到很不好,因为:
1.增加好多子类,类个数就会爆炸增长了
2.继承的扩展不够灵活,通过装饰模式,不同的具体装饰类进行排列组合达到了不同行为的组合目的
所以我们选择了装饰模式,那么好处在于:
1.需要执行特殊行为时,客户代码就可以在运行时根据需要有选择地、按顺序地使用装饰功能包装对象了[DP]
2.方便处理那些可以撤销的职责
3.有效地把类的核心职责和装饰功能区分开了,而且可以去除相关类中重复的装饰逻辑。
4.每个对象只关心自己的功能,不需要关心如何被添加到对象链中[DPE]
5.*将继承中对子类的扩展转化为功能类的组合,从而将需要对子类的扩展转嫁给用户去进行调用组合,用户如何组合由用户决定。
看看我的代码
Component类提供了抽象接口给DecoratorA/DecoratorB类,这样的话,Decorator类就对于Component类透明了,外部扩展了Component类
class DecoratorA : public Component
{
private:
Component *DecoComponent;
}
接口上,Decorator表现为“is-a”的继承关系,实现上,表现为“has-a”的组合关系
class DecoratorA : public Component
{
public:
void Operation(){DecoComponent->Operation();}
}
不必注意到底是怎么添加到对象链中的
ConcreteDectoratorA(Component *DecoComponent) : DecoratorA(DecoComponent){}
DecoratorA(Component *pComponent) : DecoComponent(pComponent){}
//问题
1.
Q:用装饰模式需要注意什么?
A:第一,如果只有一个ConcreteComponent而没有抽象Component,那么Decorator直接继承ConcreteComponent,同理,只有一个ConcreteDecorator,没必要创建Decorator
第二,保持Component的简洁性,不要使其过于复杂
2.
Q:装饰模式有缺点吗?
A:有。因为装饰模式产生很多相似对象,查错时候会变得难。
3.
Q:什么时候用装饰模式?
A:简单来说,你在 有一些要动态添加或扩展给对象的功能 而 又需要把这些功能按正确的顺序串联起来进行控制 的时候用(纵使这些功能排序千变万化)。