介绍
- 扩展类型可以通过继承来实现, 但很多时候我们需要为对象动态添加一些部件, 用继承实现的话可能会造成子类的膨胀, 而且也没有必要专门为一种对象设立一种类型, 比如现在有一个文本框类, 现在需要需要一个带滑动条的文本框 或是一中带按钮与滑动条的文本框, 显然由于需求的经常变化, 如果采用继承来提供这样的对象是不合理的, 采用装饰模式, 只要对文本框对象动态的添加上相应的部件即可.
适用
- 在不影响其他对象的情况下, 以动态 透明的方式给单个对象添加职责;
- 处理那些可以撤销对象职责的情况;
- 当新添加类型不能或不宜采用子类的方法进行扩充, 如组合可能会产生大量独立的子类, 或应类型被隐藏或类定义不能产生子类的情况;
例子
- 小明和小梦买了一套房Home, 现在他们想要装修大厅Parlor, 小明决定在电视背景墙上应该装上一面山水瓷画LandscapeBkgrdPts, 小梦想在天花板装上一漂亮的吊灯Chandelier, 装修好后过了几天, 小梦又想装一粉红色窗帘PinkCurtain, 小明想在大厅的角楼放上一盆栽potted, …..
分析
- 显然例子中小两口想把房子装修的漂亮些, 会对大厅, 卧室进行各种装修, 添加各种部件, 甚至后面还会继续修改, 这样我们就不可能每次修改就把房子设计成一个新的类, 我们只需把房间Room抽象出来, 将客厅Hall, 卧室BeddingRoom继承房间, 再通过装修类Decoration来对这些对象进行装修, 而具体的装修方法则只是将Room对象进行一层层的包装;
代码
// 房间抽象类
class Room
{
public:
virtual void Decoratting() = 0;
};
// 什么房间
class Hall : public Room
{
public:
virtual void Decoratting()
{
cout<<"Decorate the Hall..."<<endl;
}
};
class BedRoom : public Room
{
public:
virtual void Decoratting()
{
cout<<"Decorate the bedroom..."<<endl;
}
};
// 装饰类接口
class Decorator : public Room
{
public:
Decorator(){};
virtual void Decoratting()
{
if(mRoom)
mRoom->Decoratting();
cout<<"decorate the rooms!"<<endl;
};
void SetRoom(Room* room)
{
mRoom = room;
}
private:
Room* mRoom;
};
// 具体的装饰方法
class Parlor : public Decorator
{
public:
Parlor(Room* r){SetRoom(r);};
virtual void Decoratting()
{
Decorator::Decoratting();
AddParlor();
cout<<"---------------------------"<<endl;
}
private:
void AddParlor()
{
cout<<" add the parlor on the wall!"<<endl;
}
};
class LandscapeBkgrdPts : public Decorator
{
public:
LandscapeBkgrdPts(Room* r){SetRoom(r);};
virtual void Decoratting()
{
Decorator::Decoratting();
AddLdscpBkgrdPts();
cout<<"---------------------------"<<endl;
}
private:
void AddLdscpBkgrdPts()
{
cout<<"add the landscape background painting"<<endl;
}
};
class PinkCurtain : public Decorator
{
public:
PinkCurtain(Room* r){SetRoom(r);};
virtual void Decoratting()
{
Decorator::Decoratting();
AddPinkCurtain();
cout<<"---------------------------"<<endl;
}
private:
void AddPinkCurtain()
{
cout<<"add the pink curtain!"<<endl;
}
};
结果
int main()
{
Room* pHall = new Parlor(new PinkCurtain(new LandscapeBkgrdPts(new Hall)));
pHall->Decoratting();
return 0;
}
总结
- 每一次添加部件都是通过Decorator父类指针来指向被包装对象;
- 每添加一层包装, 就添加了一层统一虚函数接口Decoratting(), 当调用该函数时就会一层一层父类(里层包装对象)被调用!