菜鸟笔记
提升您的技术认知

c 设计模式——组合模式-ag真人游戏

阅读 : 450

问题描述

上图,是一个公司的组织结构图,总部下面有多个子公司,同时总部也有各个部门,子公司下面有多个部门。如果对这样的公司开发一个oa系统,作为程序员的你,如何设计这个oa系统呢?先不说如何设计实现,接着往下看,看完了下面的内容,再回过头来想怎么设计这样的oa系统。

什么是组合模式?

在gof的《设计模式:可复用面向对象软件的基础》一书中对组合模式是这样说的:将对象组合成树形结构以表示“部分-整体”的层次结构。组合(composite)模式使得用户对单个对象和组合对象的使用具有一致性。

组合模式(composite)将小对象组合成树形结构,使用户操作组合对象如同操作一个单个对象。组合模式定义了“部分-整体”的层次结构,基本对象可以被组合成更大的对象,而且这种操作是可重复的,不断重复下去就可以得到一个非常大的组合对象,但这些组合对象与基本对象拥有相同的接口,因而组合是透明的,用法完全一致。

我们这样来简单的理解组合模式,组合模式就是把一些现有的对象或者元素,经过组合后组成新的对象,新的对象提供内部方法,可以让我们很方便的完成这些元素或者内部对象的访问和操作。我们也可以把组合对象理解成一个容器,容器提供各种访问其内部对象或者元素的api,我们只需要使用这些方法就可以操作它了。

uml类图

component:

  1. 为组合中的对象声明接口;
  2. 在适当的情况下,实现所有类共有接口的缺省行为;
  3. 声明一个接口用于访问和管理component的子组件。

leaf:

  1. 在组合中表示叶节点对象,叶节点没有子节点;
  2. 在组合中定义叶节点的行为。

composite:

  1. 定义有子部件的那些部件的行为;
  2. 存储子部件。

client:

通过component接口操作组合部件的对象。

代码实现

/*
** filename     : compositepatterndemo
** description  : more information, please go to https://www.coonote.com
*/
#include 
#include 
#include 
using namespace std;
// 抽象的部件类描述将来所有部件共有的行为
class component
{
  
public:
     component(string name) : m_strcompname(name){}
     virtual ~component(){}
     virtual void operation() = 0;
     virtual void add(component *) = 0;
     virtual void remove(component *) = 0;
     virtual component *getchild(int) = 0;
     virtual string getname()
     {
  
          return m_strcompname;
     }
     virtual void print() = 0;
protected:
     string m_strcompname;
};
class leaf : public component
{
  
public:
     leaf(string name) : component(name)
     {}
     void operation()
     {
  
          cout<<"i'm "<::iterator it = m_veccomp.begin();
          while (it != m_veccomp.end())
          {
  
               if (*it != null)
               {
  
                    cout<<"----delete "<<(*it)->getname()<<"----"<::iterator it = m_veccomp.begin(); it != m_veccomp.end();   it)
          {
  
               if ((*it)->getname() == pcomponent->getname())
               {
  
                    if (*it != null)
                    {
  
                         delete *it;
                         *it = null;
                    }
                    m_veccomp.erase(it);
                    break;
               }
          }
     }
     component *getchild(int index)
     {
  
          if (index > m_veccomp.size())
          {
  
               return null;
          }
          return m_veccomp[index - 1];
     }
     void print()
     {
  
          for (vector::iterator it = m_veccomp.begin(); it != m_veccomp.end();   it)
          {
  
               cout<<(*it)->getname()< m_veccomp;
};
int main(int argc, char *argv[])
{
  
     component *pnode = new composite("beijing head office");
     component *pnodehr = new leaf("beijing human resources department");
     component *psubnodesh = new composite("shanghai branch");
     component *psubnodecd = new composite("chengdu branch");
     component *psubnodebt = new composite("baotou branch");
     pnode->add(pnodehr);
     pnode->add(psubnodesh);
     pnode->add(psubnodecd);
     pnode->add(psubnodebt);
     pnode->print();
     component *psubnodeshhr = new leaf("shanghai human resources department");
     component *psubnodeshcg = new leaf("shanghai purchasing department");
     component *psubnodeshxs = new leaf("shanghai sales department");
     component *psubnodeshzb = new leaf("shanghai quality supervision department");
     psubnodesh->add(psubnodeshhr);
     psubnodesh->add(psubnodeshcg);
     psubnodesh->add(psubnodeshxs);
     psubnodesh->add(psubnodeshzb);
     pnode->print();
     // 公司不景气,需要关闭上海质量监督部门
     psubnodesh->remove(psubnodeshzb);
     if (pnode != null)
     {
  
          delete pnode;
          pnode = null;
     }
     return 0;
}

实现要点

  1. composite的关键之一在于一个抽象类,它既可以代表leaf,又可以代表composite;所以在实际实现时,应该最大化component接口,component类应为leaf和composite类尽可能多定义一些公共操作。component类通常为这些操作提供缺省的实现,而leaf和composite子类可以对它们进行重定义;
  2. component是否应该实现一个component列表,在上面的代码中,我是在composite中维护的列表,由于在leaf中,不可能存在子composite,所以在composite中维护了一个component列表,这样就减少了内存的浪费;
  3. 内存的释放;由于存在树形结构,当父节点都被销毁时,所有的子节点也必须被销毁,所以,我是在析构函数中对维护的component列表进行统一销毁,这样就可以免去客户端频繁销毁子节点的困扰;
  4. 由于在component接口提供了最大化的接口定义,导致一些操作对于leaf节点来说并不适用,比如:leaf节点并不能进行add和remove操作,由于composite模式屏蔽了部分与整体的区别,为了防止客户对leaf进行非法的add和remove操作,所以,在实际开发过程中,进行add和remove操作时,需要进行对应的判断,判断当前节点是否为composite。

组合模式的优点

将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

使用场景

  1. 你想表示对象的部分-整体层次结构;
  2. 希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。

引用大话设计模式的片段:“当发现需求中是体现部分与整体层次结构时,以及你希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时,就应该考虑组合模式了。”

总结

通过上面的简单讲解,我们知道了,组合模式意图是通过整体与局部之间的关系,通过树形结构的形式进行组织复杂对象,屏蔽对象内部的细节,对外展现统一的方式来操作对象,是我们处理更复杂对象的一个手段和方式。现在再结合上面的代码,想想文章开头提出的公司oa系统如何进行设计。

网站地图