每次写博客都要出点状况,好容易写完了,电脑死机了。无奈,白费功夫。好吧,我吸取教训,先写在OneNote里面。
由于《Head first设计模式》和《大话设计模式》这两本比较通俗的书一个是Java,一个是C#,虽说原理都是一样的,但是在某些数据结构上面C++还是跟这两者有区别的,并且C++关于对象用指针还是引用的问题困扰我很久,于是边学习的同时,我用C++实现这些设计模式,也算是同时熟悉C++了。
今天学习的模式是组合模式,组合模式用于将对象组合成树形结构以表示“部分--整体”的层次结构。使得用户对单个对象和组合对象的使用具有一致性。
什么意思呢,比如公司的组成就是一个典型的树形结构,举个例子如下图:
这里每个人所扮演的角色不同,行驶的职能也不同,在写程序的时候,要区分他们需要在客户端有很多的判断语句。但是通过组合模式,就可以将他们抽象出来,不论是总经理还是职员,都是人,都具有执行任务的能力,因此可以统一抽象。并且为了能够在派生出的对象上还可以延伸出结点,因此将对象做成容器。这么说有点抽象,先看UML图:
这里Component类定义了一个结点的抽象,Operation()是具体执行的方法,Add()、Remove()、GetChild()都是为了将这个抽象做成容器而创造的方法。Leaf类为叶子结点,也就是说它不能再派生出子结点,因此它只用实现Operation()函数就行了。而Composite类则是结点类,它能够再派生出子节点,因此它要将Component类的函数全都实现。
现在来看代码吧:(声明:这些代码并非笔者原创,借鉴的成分占多数,我只是修改了其中一些部分)
首先是Component.h,它是一个纯虚函数,没有.cpp文件,并且不能用来实例化对象
#pragmaonce classComponent { public: virtual void Operation() = 0;//纯虚函数,只提供接口,没有默认实现 virtual void Add( Component *com );//增加一个Component对象 virtual void Remove( Component *com );//移除一个Component对象 virtual Component* GetChild( int index );//得到指定Component对象的指针 virtual ~Component(); protected: Component(); };
Leaf.h
#pragmaonce #include"Component.h" //Leaf是叶子结点,也就是不含有子组件的结点类,所以不用实现Add、Remove、GetChild等方法 classLeaf: public Component { public: Leaf( void ); ~Leaf( void ); virtual void Operation(); };
Leaf.cpp
#include"Leaf.h" #include<iostream> usingnamespace std; Leaf::Leaf(void ) { } Leaf::~Leaf(void ) { } voidLeaf::Operation() { cout << "Leaf::Operation"<< endl; }
Composite.h 这个类必须实现Component的所有函数。
#pragmaonce #include"Component.h" #include<vector> usingnamespace std; // 含有子组件的类 classComposite: public Component { public: Composite( void ); ~Composite( void ); void Operation(); void Add( Component *com ); void Remove( Component *com ); Component* GetChild( int index ); private: vector<Component *> m_ComVec; };
Composite.cpp
#include"Composite.h" #include<iostream> usingnamespace std; Composite::Composite(void ) { } Composite::~Composite(void ) { } voidComposite::Operation() { cout <<"Composite::Operation" << endl; vector<Component*>::iterator iter =this->m_ComVec.begin(); for ( ; iter != m_ComVec.end(); iter++ ) { ( *iter )->Operation(); } } voidComposite::Add( Component *com ) { this->m_ComVec.push_back( com ); } voidComposite::Remove( Component *com ) { vector<Component*>::iterator iter =this->m_ComVec.begin(); for ( ; iter != this->m_ComVec.end();iter++ ) { if ( *iter == com ) { this->m_ComVec.erase( iter ); iter = m_ComVec.begin(); } } } Component*Composite::GetChild( int index ) { if ( index < 0 || index >this->m_ComVec.size() ) { return NULL; } return this->m_ComVec[index]; }
#include"Composite.h" #include"Leaf.h" void main() { Composite *pRoot = newComposite(); // 创建一个根结点 pRoot->Add( new Leaf()); // 为这个根结点添加一个叶子结点 Leaf *pLeaf1 = new Leaf; // 创建两个叶子结点 Leaf *pLeaf2 = new Leaf; // pLeaf1->Operation(); // 创建一个结点,并为它加上刚创建的两个叶子结点 Composite *pCom = new Composite(); pCom->Add( pLeaf1 ); pCom->Add( pLeaf2 ); //pCom->Operation(); pRoot->Add( pCom ); // 把pCom结点添加到根结点上 pRoot->Operation(); // 这里根结点执行操作会让每个结点都执行Operation()函数 getchar(); }
这里的代码也讲的很清楚了,最后我就把main里面创建的树形结构图给出来吧: