Composite模式
一 意图
将对象组合成树形结构以表示“部分——整体”的层次结构。Composite使得用户对单个对象操作和组合对象的操作使用具有一致性。
二 动机
绘图编辑器和图形捕捉系统图形应用程序中,总是存在简单的图形到简单的组件再到复杂的组件,
但他们在本质上都是图形(各种基本的图形组合或者递归组合)。
这可以分成两个部分:基本图元和组件图形。对于基本的图元可以单独定义类;对于组件图形可以使用图元容器(Container)。
结果就是:在使用时,对于同样的都是图形的图元和组件必须加以区分对待(图元对象Or容器对象)。对于庞大的图形系统,这无疑是非常复杂的!
解决方法:Composite模式递归组合,实现系统对图元还是组件都一致性对待。
对于Line或者Rectangle或者Picture都是Graphic,都具有相同的Graphic属性。
但对于Picture来说它是组合基本图元的方式组成的组件,本身会具有新的特性。
所以在Graphic图形中存在派生类组件的结构:
三 适用性及其结构
1 表示对象的部-整体层次结构
2 忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
3 结构:
Component:为组合中的对象生命接口
在适当情况下,实现所有类共有的接口的缺省行为
声明一个接口用于访问和管理Component的子组件
在递归结构中定义一个接口,用于访问一个父部件。
Leaf:在组合中表示叶节点对象
Composite:定义所有子部件的行为,实现与子部件相关的操作。
Composite实现任意组合方式构建定制新的Component。
4 性能分析
Leaf和Composite同为Component,实际上之间是区别,Composite是各个Component的组合,
需要对各个Component进行维护,Leaf是不需要这些维护的。
所以这些维护接口是Composite自身提供还是Component提供这些维护的接口,比如:addChild,removeChild等。
透明性:由基类Component提供所有Composite需要的基本一些接口管理其中的ChildComponent,
如addChild,removeChild等,这样就Leaf或者Composite具有一致性,而在客户端无需区分Leaf还是Composite。
安全性:基类只提供Leaf相关的接口,作为Composite需要管理器中的ChildComponent需要自己提供。
保证Leaf的操作安全性。这样导致Leaf和Composite的不一致性需要区别对待,会造成系统的复杂性。
这个在应用中我觉得,如果我们大量的操作都是基于Leaf的直接使用,而很少用到Composite,可以采取安全性,
但是这造成的结果就是:扩展性非常差。但通常在使用中大多数都是基于Composite方式,便于扩展和代码重用,
所以对ChildComponent的管理是非常重要的。在系统中都可以随处可见透明性的Composite模式,以构建一颗树形的对象模型。
四 代码实现
以电脑主板为例,电脑主板包括:CPU,内存,扩展槽,芯片组,时钟发生器,IDE接口和软驱,电源模块,I/O接口……
选取其中的:CPU,芯片组,I/O接口为例
1 Equicpment基类
/*----------------------------------------------------------------*/
/* class Equipment */
/*----------------------------------------------------------------*/
class Equipment
{
#define EQUIP_MAX_NUM (5)
public:
Equipment()
{
cout<<" Equipment constructor "<<endl;
for (int i = 0 ; i < EQUIP_MAX_NUM; i++)
{
m_equip[i] = NULL;
}
}
void addChildEquip(Equipment* equip)
{
for (int i = 0 ; i < EQUIP_MAX_NUM; i++)
{
if(m_equip[i] == NULL)
{
m_equip[i] = equip;
break;
}
}
}
void removeChildEquip(Equipment* equip)
{
for (int i = 0 ; i < EQUIP_MAX_NUM; i++)
{
if(m_equip[i] == equip)
{
m_equip[i] = NULL;
break;
}
}
}
void start()
{
for (int i = 0 ; i < EQUIP_MAX_NUM; i++)
{
if (m_equip[i] != NULL)
{
m_equip[i]->startEquipment();
}
}
}
virtual void startEquipment()
{
cout<<"Equipment startEquipment"<<endl;
}
private:
Equipment* m_equip[EQUIP_MAX_NUM];
};
2 Chip基类
/*----------------------------------------------------------------*/
/* class Chip */
/*----------------------------------------------------------------*/
class Chip: public Equipment
{
public:
Chip()
{
cout<<" Chip constructor "<<endl;
}
virtual void startEquipment()
{
cout<<" Chip startEquipment "<<endl;
}
};
3 Cpu部分
//CPU部分
/*----------------------------------------------------------------*/
/* class CpuProcessor */
/*----------------------------------------------------------------*/
class CpuProcessor: public Chip
{
public:
CpuProcessor()
{
cout<<" CpuProcessor constructor "<<endl;
}
virtual void startEquipment()
{
cout<<" CpuProcessor startEquipment "<<endl;
}
};
/*----------------------------------------------------------------*/
/* class CpuSocket */
/*----------------------------------------------------------------*/
class CpuSocket: public Equipment
{
public:
CpuSocket()
{
cout<<" CpuSocket constructor "<<endl;
}
virtual void startEquipment()
{
cout<<" CpuSocket startEquipment "<<endl;
}
};
/*----------------------------------------------------------------*/
/* class CpuEquipment */
/*----------------------------------------------------------------*/
class CpuEquipment: public Equipment
{
public:
CpuEquipment()
{
cout<<" CpuEquipment constructor "<<endl<<endl;
}
void addChildCpu()
{
cout<<"-------------------addChildCpu-------------------"<<endl;
cpu = new CpuProcessor();
slot = new CpuSocket();
this->addChildEquip(cpu);
this->addChildEquip(slot);
}
virtual void startEquipment()
{
this->start();
cout<<" CpuEquipment startEquipment "<<endl<<endl;
}
private:
CpuProcessor* cpu;
CpuSocket* slot;
};
4 ChipSet部分
//ChipSet芯片组
/*----------------------------------------------------------------*/
/* class GraphicsChip */
/*----------------------------------------------------------------*/
class GraphicsChip: public Chip
{
public:
GraphicsChip()
{
cout<<" GraphicsChip constructor "<<endl;
}
virtual void startEquipment()
{
cout<<" GraphicsChip startEquipment "<<endl;
}
};
/*----------------------------------------------------------------*/
/* class SoundChip */
/*----------------------------------------------------------------*/
class SoundChip: public Chip
{
public:
SoundChip()
{
cout<<" SoundChip constructor "<<endl;
}
};
/*----------------------------------------------------------------*/
/* class ChipSet */
/*----------------------------------------------------------------*/
class ChipSet: public Equipment
{
public:
ChipSet()
{
cout<<" ChipSet constructor "<<endl<<endl;
}
void addChildChip()
{
cout<<"-------------------addChildChip-------------------"<<endl;
GraphicsChip* gChip = new GraphicsChip();
SoundChip* sChip = new SoundChip();
this->addChildEquip(gChip);
this->addChildEquip(sChip);
}
virtual void startEquipment()
{
this->start();
cout<<" ChipSet startEquipment "<<endl<<endl;
}
private:
};
5 I/O接口部分
//I/O接口
/*----------------------------------------------------------------*/
/* class IOEquipment */
/*----------------------------------------------------------------*/
class IOEquipment: public Equipment
{
public:
IOEquipment()
{
cout<<" IOEquipment constructor "<<endl;
}
virtual void startEquipment()
{
cout<<" IOEquipment startEquipment "<<endl;
}
};
/*----------------------------------------------------------------*/
/* class KeyboardIO */
/*----------------------------------------------------------------*/
class KeyboardIO: public IOEquipment
{
public:
KeyboardIO()
{
cout<<" KeyboardIO constructor "<<endl;
}
virtual void startEquipment()
{
cout<<" KeyboardIO startEquipment "<<endl;
}
};
/*----------------------------------------------------------------*/
/* class MouseIO */
/*----------------------------------------------------------------*/
class MouseIO: public IOEquipment
{
public:
MouseIO()
{
cout<<" MouseIO constructor "<<endl;
}
virtual void startEquipment()
{
cout<<" MouseIO startEquipment "<<endl;
}
};
/*----------------------------------------------------------------*/
/* class UsbIO */
/*----------------------------------------------------------------*/
class UsbIO: public IOEquipment
{
public:
UsbIO()
{
cout<<" UsbIO constructor "<<endl;
}
virtual void startEquipment()
{
cout<<" UsbIO startEquipment "<<endl;
}
};
/*----------------------------------------------------------------*/
/* class IOEquipmentSet */
/*----------------------------------------------------------------*/
class IOEquipmentSet: public Equipment
{
public:
IOEquipmentSet()
{
cout<<" IOEquipmentSet constructor "<<endl<<endl;
}
void addChildIO()
{
cout<<"-------------------addChildIO-------------------"<<endl;
KeyboardIO* kIO = new KeyboardIO();
MouseIO* mIO = new MouseIO();
UsbIO* uIO = new UsbIO();
this->addChildEquip(kIO);
this->addChildEquip(mIO);
this->addChildEquip(uIO);
}
virtual void startEquipment()
{
this->start();
cout<<" IOEquipmentSet startEquipment "<<endl<<endl;
}
};
6 MotherboardEquipment 主板
//主板
/*----------------------------------------------------------------*/
/* class IOEquipmentSet */
/*----------------------------------------------------------------*/
class MotherboardEquipment: public Equipment
{
public:
MotherboardEquipment()
{
cout<<" MotherboardEquipment constructor "<<endl<<endl;
}
void addAllChildEquip()
{
cout<<"-------------------addAllChildEquip-------------------"<<endl;
CpuEquipment* cpuEquip = new CpuEquipment();
cpuEquip->addChildCpu();
ChipSet* chipEquip = new ChipSet();
chipEquip->addChildChip();
IOEquipmentSet* ioEquip = new IOEquipmentSet();
ioEquip->addChildIO();
this->addChildEquip(cpuEquip);
this->addChildEquip(chipEquip);
this->addChildEquip(ioEquip);
}
};
例子可能并非很完善和合理,仅仅是为了演示一下Composite模式。
五 实例分析
将以手机上屏幕显示控件为例。控件涉及到UI显示布局和消息传递处理(按键触屏)
在Frame类中通过众多基类指针,将所有的对象组成一个树形结构。有助于对象管理和内存管理。
如果父类对象释放那么其子对象没有存在的必要了,根据这棵树就能遍历所有子对象,并将其释放掉
(当然并不是在这里,这里仅包含的是Frame对象的树结构)主要是用于界面显示布局层次和消息传递响应。