组合模式又叫部分整体模式,它创建了对象组的树形结构,将对象组合成树状结构,以一致的方式处理叶子对象以及组合对象,不以层次高低定义类,都是结点类
一、传统组合模式
举例,大学、学院、系,它们之间不是继承关系,是组合关系:大学由学院组成,学院由系组成,但是它们都是组织结点,一个大学,n个学院,一个学院m个系,大学、学院是 组合类型的,它们都包含结点成员,系是 叶子类型 的,不包含结点成员
把大学类、学院类、系类抽象为组织结点类,它们都是组织结点类的子类(其中大学子类、学院子类是组合类型的类,系是叶子类型的类),按照具体依赖抽象原则,以子类共有的属性和行为来定义结点类,代码如下:
//组织结点(基类)Organization
class Organization{ //具体依赖抽象原则std::string name;//数据成员
public:Organization( std::string name):name(name) { }//构造函数virtual ~Organization(){ } //虚析构//其他成员函数virtual std::string getName(){ return name; } virtual void add(Organization* o){ throw "叶子结点没有成员!\n"; }//virtual void remove( ){ throw "叶子结点没有成员!\n"; }virtual void print() = 0; //
};
组合类型的子类University、College,重写基类成员函数,代码几乎一样
//组合类型(子类)University College
//University
class University:public Organization{std::list<Organization*> ul; //以基类的形式包含其他子类对象
public:University(std::string name):Organization(name) { }~University(){std:: cout << "~University\n";for(auto o:ul){ delete o; } }//重写virtual void add(Organization* o){ul.push_back(o);}virtual void print(){std::cout << getName() << "\n";//基类成员获取,基类的成员也是子类的组成部分for( auto o:ul ){o->print();}}
};//College
class College:public Organization{std::list<Organization*> cl; //以基类的形式包含其他子类对象
public:College(std::string name):Organization(name) { }~College(){std:: cout << "~College\n";for(auto o:cl){ delete o; } }//重写virtual void add(Organization* o){cl.push_back(o);}virtual void print(){std::cout << getName() << "\n";//基类成员获取,基类的成员也是子类的组成部分for( auto o:cl ){o->print();}}
};
叶子类型的子类(Department)
//叶子类型(子类)Department
class Department:public Organization{
public:Department(std::string name):Organization(name) { }~Department(){std:: cout << "~Department\n";}//重写virtual void print(){std::cout << getName() << "\n";}
};
头文件及测试代码
#include <iostream>
#include <string>
#include <exception>
#include <list>int main()
{University u("清华大学");Organization* c1 = new College("计算机学院");Organization* c2 = new College("信息工程学院");Organization* d = new Department("信息工程");u.add( c1 );u.add( c2 );c2->add( d );u.print();//c2->print(); return 0;
}
二、组合模式的结点设计
把组合类型的的属性、行为都放到结点,以对象组是否为空来判断是叶子类型的还是组合类型的,这样叶子类型也可以扩展为组合类型,虽然看起来有点混乱,但是确实可行,比如系原来是叶子,现在有了个学生会,添加成员后就可以不是叶子了
#include <iostream>
#include <string>
#include <exception>
#include <list>//组织结点(基类)Organization
class Organization{ //具体依赖抽象原则std::string name;//数据成员std::list<Organization*> ol; //对象组
public:Organization( std::string name):name(name) { } //构造函数virtual ~Organization(){ //虚析构for(auto o:ol){ delete o; } } //其他成员函数 virtual void add(Organization* o){ ol.push_back(o); } virtual void print(){std::cout << name << "\n";if( !ol.empty() ) //判断是否是叶子结点{ for( auto o:ol ){o->print();}} }
}; //University
class University:public Organization{
public:University(std::string name):Organization(name) { }~University(){ std:: cout << "~University\n"; }
};//College
class College:public Organization{std::list<Organization*> cl; //以基类的形式包含其他子类对象
public:College(std::string name):Organization(name) { }~College(){std:: cout << "~College\n";}
};//Department
class Department:public Organization{
public:Department(std::string name):Organization(name) { }~Department(){std:: cout << "~Department\n";}
};//StudentUnion
class StudentUnion:public Organization{
public:StudentUnion(std::string name):Organization(name) { }~StudentUnion(){std:: cout << "~StudentUnion\n";}
};int main()
{University u("清华大学");Organization* c1 = new College("计算机学院");Organization* c2 = new College("信息工程学院");Organization* d1 = new Department("信息工程");Organization* d2 = new Department("软件工程");Organization* s = new StudentUnion("信息工程学生会");d1->add( s );c1->add( d2 );c2->add( d1 );u.add( c1 );u.add( c2 );u.print( );//c2->print( ); return 0;
}
三、修改打印函数,打印出树形结构
1、 修改print
virtual void print( int depth ){for(int i=0; i< depth; ++i)std:: cout << "--";std::cout << name << "\n";if( !ol.empty() ) //判断是否是叶子结点{ for( auto o:ol ){o->print(depth+1);}} }
2、调用修改为
u.print(0);
//c2->print( 0 );