设计模式——组合模式
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式——组合模式相关的知识,希望对你有一定的参考价值。
设计模式(十二)——组合模式
一、组合模式简介
1、组合模式简介
组合模式将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。
组合模式为解决组件之间的递归组合提供了解决的办法,主要分为两个派生类:
A、Leaf是叶子结点,是不含有子组件的结点
B、Composite是含有子组件的类
组合模式有透明组合模式和安全组合模式两种模式。
透明组合模式特点:
A、在Component中定义了用于访问和管理子构件的接口,好处是确保所有的构件类都有相同的接口。
B、在Client看来,Leaf与Composite所提供的接口一致,Client可以相同地对待所有的对象。
安全组合模式特点:
在Component中不定义任何用于访问和管理子构建的接口,而在 Composite中声明并实现。因为不需要向Leaf提供管理成员对象的接口,对于Leaf来说,Client不可能调用到管理子构件对象的接口。
透明组合模式和安全组合模式的区别:
A、透明组合模式的缺点是不够安全,因为Leaf和Composite在本质上是有区别的。Leaf不可能有下一个层级,因此为其提供add()、remove()、getChild() 等接口没有意义。在运行阶段如果调用这些接口可能会出错(如果没有提供相应的异常处理)。
B、安全组合模式的缺点是不够透明,因为Leaf和Composite具有不同的接口,且Composite中用于访问和管理子构件的接口没有在Component中定义,因此Client不能完全针对抽象编程,必须有区别地对待Leaf和 Composite。
组合模式的UML图:
在Component中声明所有用来管理子对象的方法,其中包括add、remove、getChild,实现Component接口的所有子类都具备了add、remove、getChild。好处就是叶节点和子节点对于外界没有区别,具备完全一致的行为接口。但因为Leaf类本身不具备add()、remove()、getChild()方法的功能,所以Leaf类继承的Component基类的add、remove、getChild是没有意义的。
2、组合模式角色
Component抽象构件:为组合中的对象声明接口,实现所有类共有接口的默认行为(add、remove、getChild)。声明一个接口用于访问和管理Component 的子部件。
Component::operatation:定义了各个组件共有的行为接口,由各个组件的具体实现
Component::add添加一个子组件
Component::remove::删除一个子组件.
Component::getChild:获得子组件的指针
Leaf叶子节点:在组合中是叶节点对象,叶节点没有子节点。
Composite枝构件:定义有子节点行为,用来存储子部件,重新实现在Component接口中与子部件有关的操作,比如add、remove、getChild、operation。
3、组合模式优缺点
优点:
A、组合模式清晰地定义了包含基本对象(Leaf)和组合对象(Composite)的类层次结构的复杂对象。基本对象可以被组合成更复杂的组合对象,而组合对象又可以被组合,客户代码可以忽略层次的差异,任何用到基本对象的地方都可以使用组合对象,方便对整个层次结构进行控制。
B、用户不用关心到底是处理一个叶子节点还是处理一个组合组件。
C、组合模式让客户可以一致的使用组合结构和单个对象。
D、在组合模式中,增加新的叶子构件和容器构件很方便,无须对现有类进行任何修改,符合“开闭原则”。
E、为树形结构提供了一种灵活的解决方案,通过递归组合容器对象和叶子对象,可以形成复杂的树形结构,但对树形结构的控制却非常简单。
缺点:
使设计变得更加抽象,对象的业务规则如果很复杂,则实现组合模式具有很大挑战性,而且不是所有的方法都与叶子对象子类都有关联。
4、组合模式使用场景
组合模式使用场景:
A、当发现需求中是体现部分与整体层次的结构时,以及希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时,应该考虑用组合模式。
B、基本对象可以被组合成更复杂的组合对象,而组合对象又可以被组合,客户代码中,任何用到基本对象的地方都可以使用组合对象。
二、 组合模式实现
Component抽象类:
#ifndef COMPONENT_H
#define COMPONENT_H
#include <iostream>
using namespace std;
//Component抽象基类,为组合中的对象声明接口,声明了类共有接口的缺省行为(add,remove,getChild函数),
//声明一个接口函数可以访问Component的子组件
class Component
{
public:
//纯虚函数,只提供接口,没有默认的实现
virtual void operation() = 0;
// 虚函数,提供接口,默认的实现打印当前调用函数
virtual void add(Component* com)
{
cout << "Component::add" << endl;
}
virtual void remove(Component* com)
{
cout << "Component::remove" << endl;
}
virtual Component* getChild(int index)
{
cout << "Component::getChild" << endl;
}
protected:
//只可以被子类调用,不对外开放
Component(){}
};
#endif // COMPONENT_H
Leaf叶子节点类:
#ifndef LEAF_H
#define LEAF_H
#include "Component.h"
//Leaf是叶子结点,是不含有子组件的结点类,继承基类add、remove、getChild方法
class Leaf : public Component
{
public:
Leaf(){}
//需要实现基类的operation接口
virtual void operation()
{
cout << "Leaf::operation" << endl;
}
};
#endif // LEAF_H
Composite类:
#ifndef COMPOSITE_H
#define COMPOSITE_H
#include "Component.h"
#include <vector>
//Composite:含有子组件的类
class Composite : public Component
{
public:
//实现所有接口
void operation()
{
cout << "Composite::operation" << endl;
vector<Component*>::iterator iter = this->m_comVec.begin();
for(iter;iter!= this->m_comVec.end();iter++)
{
(*iter)->operation();
}
}
void add(Component* com)
{
cout << "Composite::add an component" << endl;
m_comVec.push_back(com);
}
void remove(Component* com)
{
cout << "Composite::remove an component" << endl;
vector<Component*>::iterator iter = this->m_comVec.begin();
for(iter;iter!= this->m_comVec.end();iter++)
{
if(*iter == com)
m_comVec.erase(iter);
}
}
Component* getChild(int index)
{
if(index < 0 || index > this->m_comVec.size())
{
return NULL;
}
return this->m_comVec[index];
}
private:
//vector来保存子组件
vector<Component*> m_comVec;
};
#endif // COMPOSITE_H
客户调用程序:
#include "Composite.h"
#include "Leaf.h"
int main()
{
//不管是叶子Leaf还是Composite对象pRoot、pCom都实现了operation接口,可以一致对待,
//直接调用operation(),体现了“使得用户对单个对象和组合对象的使用具有一致性。”
Composite* pRoot = new Composite();
//组合对象添加叶子节点
pRoot->add(new Leaf());
Leaf* pLeaf1 = new Leaf();
Leaf* pLeaf2 = new Leaf();
//叶子节点只实现了operation方法,其他add、remove、getChild都继承自基类
pLeaf1->add(pLeaf2);//执行基类add
pLeaf1->remove(pLeaf2);//执行基类remove
//执行叶子Operation操作
pLeaf1->operation();
//组合对象实现了基类Component的所有接口
Composite* pCom = new Composite();
//组合对象添加叶子节点
pCom->add(pLeaf1);
//组合对象添加叶子节点
pCom->add(pLeaf2);
//执行组合对象Operation操作
pCom->operation();
//组合对象添加组合对象
pRoot->add(pCom);
//执行组合对象Operation操作
pRoot->operation();
return 0;
}
三、组合模式实例
一个集团公司,有一个母公司,下设很多家子公司。不管是母公司还是子公司,都有各自直属的财务部、人力资源部、销售部等。对于母公司来说,不论是子公司,还是直属的财务部、人力资源部,都是子部门。整个公司的部门拓扑图就是一个树形结构。
Company公司抽象类:
#ifndef COMPANY_H
#define COMPANY_H
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
//公司抽象类
class Company
{
public:
Company(string name)
{
m_name = name;
}
//增加节点
virtual void add(Company* com) = 0;
//显示
virtual void show(int depth) = 0;
//删除节点
virtual void remove(Company* com) = 0;
//职责
virtual void duty() = 0;
bool operator==(const Company& com)
{
return m_name == com.m_name;
}
protected:
string m_name;
};
#endif // COMPANY_H
ConcreteCompany具体公司类:
#ifndef CONCRETECOMPANY_H
#define CONCRETECOMPANY_H
#include "Company.h"
#include <list>
//具体公司类
class ConcreteCompany : public Company
{
public:
ConcreteCompany(string name):Company(name)
{
m_childs = new list<Company*>;
}
~ConcreteCompany()
{
for(list<Company*>::iterator it = m_childs->begin(); it != m_childs->end(); it++)
delete *it;
delete m_childs;
}
//增加子节点
void add(Company* com)
{
m_childs->push_back(com);
}
//删除子节点
void remove(Company* com)
{
for(list<Company*>::iterator it = m_childs->begin(); it != m_childs->end(); it++)
{
if(**it == *com)
{
m_childs->erase(it);
break;
}
}
}
//显示本节点的子节点
void show(int depth)
{
for(int i = 0;i < depth; i++)
std::cout<<"-";
//显示公司节点名称
std::cout << m_name << std::endl;
for(list<Company*>::iterator it = m_childs->begin(); it != m_childs->end(); it++)
(*it)->show(depth + 4);//显示本节点的子节点名称
}
//显示子节点的职责
void duty()
{
for(list<Company*>::iterator it = m_childs->begin(); it != m_childs->end(); it++)
(*it)->duty();//显示本节点的子节点职责
}
private:
list<Company*>* m_childs;
};
#endif // CONCRETECOMPANY_H
FinanceDepartment财务部门类:
#ifndef FINANCEDEPARTMENT_H
#define FINANCEDEPARTMENT_H
#include "Company.h"
using namespace std;
//公司财务部门
class FinanceDepartment: public Company
{
public:
FinanceDepartment(string name):Company(name){}
void add(Company* com)
{
}
void remove(Company* com)
{
}
//显示财务部门名称
void show(int depth)
{
for(int i = 0;i < depth; i++)
std::cout<<"-";
std::cout << m_name << std::endl;
}
//显示财务部分职责
void duty()
{
std::cout<< m_name <<" Financial Management"<<std::endl;
}
};
#endif // FINANCEDEPARTMENT_H
HRDepartment人力资源部门类:
#ifndef HRDEPARTMENT_H
#define HRDEPARTMENT_H
#include "Company.h"
class HRDepartment : public Company
{
public:
HRDepartment(string name):Company(name){}
//显示人力资源部分名称
void show(int depth)
{
for(int i=0;i < depth;i++)
std::cout<<"-";
std::cout<< m_name <<std::endl;
}
void add(Company* com)
{
}
void remove(Company* com)
{
}
//显示人力资源部分职责
void duty()
{
std::cout<< m_name <<" staff recruitment and employment"<<std::endl;
}
};
#endif // HRDEPARTMENT_H
客户调用程序:
#include "Company.h"
#include "ConcreteCompany.h"
#include "FinanceDepartment.h"
#include "HRDepartment.h"
int main()
{
//北京总公司
Company* root = new ConcreteCompany("BeiJing Head Office");
root->add(new HRDepartment("HRDepartment of Head Office"));
root->add(new FinanceDepartment("FinanceDepartment of Head Office"));
//华东上海分公司
Company* ShangHaicomp=new ConcreteCompany("China East ShangHai Branch Office");
ShangHaicomp->add(new HRDepartment("HRDepartment of ShangHai Branch Office"));
ShangHaicomp->add(new FinanceDepartment("FinanceDepartment of ShangHai Branch Office"));
//华东分公司隶属北京总公司
root->add(ShangHaicomp);
//华东分公司南京办事处
Company* NanJingOffice=new ConcreteCompany("NanJing Office");
NanJingOffice->add(new HRDepartment("HRDepartment of NanJing Office"));
NanJingOffice->add(new FinanceDepartment("FinanceDepartment of NanJing Office"));
//南京办事处隶属华东分公司
ShangHaicomp->add(NanJingOffice);
//西南成都分公司
Company* ChengDucomp=new ConcreteCompany("China SouthWest ChengDu Branch Office");
ChengDucomp->add(new HRDepartment("HRDepartment of ChengDu Branch Office"));
ChengDucomp->add(new FinanceDepartment("FinanceDepartment of ChengDu Branch Office"));
//西南分公司隶属北京总公司
root->add(ChengDucomp);
Company* KunMingOffice=new ConcreteCompany("KunMing Office");
KunMingOffice->add(new HRDepartment("HRDepartment of KunMing Office"));
KunMingOffice->add(new FinanceDepartment("FinanceDepartment of KunMing Office"));
//昆明办事处隶属西南分公司
ChengDucomp->add(KunMingOffice);
//显示公司的树形结构
std::cout<<"Structure:"<<std::endl;
root->show(1);
//显示公司所有部门的职责
std::cout<<std::endl<<"Duty:"<<std::endl;
root->duty();
delete KunMingOffice,ChengDucomp;
delete NanJingOffice,ShangHaicomp;
delete root;
return 0;
}
本文出自 “生命不息,奋斗不止” 博客,谢绝转载!
以上是关于设计模式——组合模式的主要内容,如果未能解决你的问题,请参考以下文章