本文是学习刘伟技术博客和《设计模式-可复用面向对象软件的基础》笔记,博客链接:http://blog.csdn.net/lovelion/article/details/17517213
主要是对博客和书本做提炼和记录,更多是对设计模式的基础框架学习,细节将略去,侧重对每个设计模式框架的理解。
我应该理解和掌握的:
1)能够画出这个设计模式的架构框图;
2)能够根据架构框图写出对应的伪代码;
3)这个模式的应用场景,主要优缺点。
1.组合模式(Composite)
软件中随处可以树形结构,最常见的如文件的目录结构。组合模式便是为了解决一致性的处理整个树形结构或者树形结构的一部分,通俗的说是一致性的处理容器类节点(文件夹,包含子节点的节点)和叶子节点(文件,不带子节点的节点)。比如我们要对文件夹进行遍历,如果存在子文件夹则打开其子文件夹继续遍历。组合模式描述了如何将容器和叶子进行递归组合,使得用户在使用时无需对他们进行区分,可以一致的对待容器。
(1)定义
组合模式:将对象组合成树形结构以表示“部分-整体”的层次结构;使得用户对单个对象和组合对象的使用具有一致性。又称“整体-部分“模式。
1)组合模式结构图如下:(引入抽象构建类Component,是所有容器类和叶子类的公共父类,客户端针对Component进行编程)
2)参与者:
a) Component(抽象构件):为组合中的对象声明接口,适当情况下,可以设置缺省行为,声明接口用于访问和管理Component的子组件。
b) Leaf(叶子构件):组合中表示叶子节点对象,没有子节点。
c) Composite(容器构件):容器节点对象,提供一个集合存储子部件,并实现那些访问和管理子构建的方法,在业务方法中可以递归调用其子节点的业务方法。
d) 组合模式的关键是定义了一个抽象构建类,它既可以代表叶子,又可以代表容器,而客户端针对抽象构建类进行编程,无需知道是叶子还是容器,可以统一进行处理。
e) 看图写代码:
/*
** FileName : CompositePatternDemo
** Author : lin005
** Date : 2015/01/27
** Description : More information, please go to http://blog.csdn.net/amd123456789
*/
//抽象类,子节点和容器的抽象
class Component
{
public:
Component(string name):m_str_name(name){}
~Component(){}
virtual void operation() = 0;//业务方法
virtual void add(Component* c) = 0;//容器类管理子构件的方法
virtual void remove(Component* c) = 0;//容器类管理子构件的方法
virtual Component* getChild(int i) = 0;
virtual string getName(){return m_str_name;}
protected:
string m_str_name;
};
//叶子节点类
class Leaf:public Component
{
public:
Leaf(string name):Component(name){}
void operation()//叶子的业务方法
{
cout<<"I am a leaf called "<<m_str_name<<endl;
}
void add(Component* c)
{
cout<<"leaf have no add function"<<endl;
}
void remove(Component* c)
{
cout<<"leaf have no remove function"<<endl;
}
virtual Component* getChild(int i)
{
cout<<"leaf have no child!"<<endl;
return NULL;
}
};
//容器类
class Composite:public Component
{
public:
Composite(string name):Component(name){}
void operation()//容器的业务方法
{
cout<<"I am a Composite called "<<m_str_name<<endl;
for(vector<Component*>::iterator it = m_vecComp.begin(); it != m_vecComp.end(); ++it)
{
(*it)->operation();//递归调用
}
}
void add(Component* c)
{
m_vecComp.push_back(c);
}
void remove(Component* c)
{
for(vector<Component*>::iterator it = m_vecComp.begin(); it != m_vecComp.end(); ++it)
{
if(!(*it)->getName().compare(c->getName()))
{
if(*it != NULL)
{
delete *it;
*it = NULL;
}
m_vecComp.erase(it);
break;
}
}
}
Component* getChild(int i)
{
if(i > m_vecComp.size())
return NULL;
return m_vecComp[i - 1];
}
~Composite()
{
vector<Component*>::iterator it = m_vecComp.begin();
while(it != m_vecComp.end())
{
if(*it != NULL)
{
cout<<"delete component called "<<m_str_name<<endl;
delete *it;
*it = NULL;
}
m_vecComp.erase(it);
it = m_vecComp.begin();
}
}
private:
vector<Component*> m_vecComp;//存储子节点
};
//客户端测试
int main()
{
//客户端针对抽象编程
//创建文件夹
Component *floder = new Composite("Floder");
Component *floder1 = new Composite("Floder1");
Component *floder2 = new Composite("Floder2");
//创建文件
Component *file1 = new Leaf("file1");
Component *file2 = new Leaf("file2");
Component *file3 = new Leaf("file3");
Component *file4 = new Leaf("file4");
Component *file5 = new Leaf("flie5");
//文件夹添加文件
floder1->add(file1);
floder1->add(file2);
floder2->add(file3);
floder2->add(file4);
//入口文件夹添加文件和文件夹
floder->add(floder1);
floder->add(floder2);
floder->add(file5);
//遍历
floder->operation();
if(floder != NULL)
{
delete floder;
floder = NULL;
}
return 0;
}
f ) 组合模式又分透明组合模式和安全组合模式,顾名思义:
透明组合模式结构图如下:
安全组合模式:
(2)总结
1)优点
a) 定义了包含基本对象和组合对象的类层次结构,让客户忽略层次的差异,方便地整个层次结构进行控制。
b) 简化了客户端代码,客户可以一致的使用组合结构和单个对象,无须知道是叶子节点还是容器节点。
c) 符合开闭原则,容易增加新的叶子和容器构件。
d) 基本对象可以被组合成更复杂的组合对象,而这个组合对象又可以被组合,这样不断的递归下去。
2) 缺点
a) 容易增加新组建也会产生一些问题,很难限制组合中的组件。
(3)适用场景
1)你想表示对象的部分-整体层次结构。
2)你希望用户忽略组合对象和单个对象的不同,用户将统一地使用组合结构中的所有对象。
3)在一个面向对象语言开发的系统中,需要处理一个树形结构。
4)在一个系统中能够分离出叶子对象和容器对象,而且他们的类型不固定,需要增加一些新的 类型。