COM复用的中Containment(包容)和Aggregation(聚合)的实现

转载 2005年02月27日 11:09:00
  1. Containment是一种比较简单的复用方法,如果Component B复用Component A,Component B实际上是Component A的一个客户,Component B向客户提供的Component A的功能实际上是Component B直接调用Component A完成的。当然Component B可以扩充Component A的功能。Component B可以直接使用已经存在的Component A,而不需要对Component A做任何改动
  2. Containment的例子实现略(潘爱民《COM原理与应用》第四章)
  3. Aggregation则比较复杂,Component A必须能够适应被Aggregation下的特殊处理。其核心在于QueryInterface函数。Aggregation涉及到聚合对象和被聚合对象双方的协作,体现了真正意义上的COM复用,而Containment只是客户程序和Component的嵌套这是Containment和Aggregation的本质区别
  4. Aggregation的实现(摘自潘爱民《COM原理与应用》)。
    Component A的Code
    class INondelegatingUnknown
    {
    public:
           virtual HRESULT  __stdcall  NondelegationQueryInterface(const IID& iid, void **ppv) = 0 ;
           virtual ULONG       __stdcall  NondelegatingAddRef() = 0;
           virtual ULONG       __stdcall  NondelegationRelease() = 0;
    };
    class CA : public ISomeInterface, public INondelegatingUnknown
    {
    protected:
         ULONG           m_Ref;
    public:
         CA(IUnknown *pUnknownOuter);
         ~CA();
    public :
           // Delegating IUnknown
           virtual HRESULT      __stdcall  QueryInterface(const IID& iid, void **ppv) ;
           virtual ULONG         __stdcall  AddRef() ;
           virtual ULONG         __stdcall  Release() ;
           // Nondelegating IUnknown
           virtual HRESULT   __stdcall  NondelegationQueryInterface(const IID& iid, void **ppv);
           virtual ULONG         __stdcall  NondelegatingAddRef();
           virtual ULONG         __stdcall  NondelegationRelease();
           virtual HRESULT   __stdcall SomeFunction( ) ;
           private :
                  IUnknown  *m_pUnknownOuter;  // pointer to outer IUnknown
    };
    // Implemention of class CA
    CA::CA (IUnknown *pUnknownOuter)
    {
           m_Ref = 0;
           g_CompANumber ++ ;
           m_pUnknownOuter = pUnknownOuter;
    }
    CA::~CA()
    {}
    ULONG CA::NondelegatingAddRef()
    {
           m_Ref ++;
           return  (ULONG) m_Ref;
    }
    ULONG CA::NondelegationRelease ()
    {
           m_Ref --;
           if (m_Ref == 0 )
           {
                  g_CompANumber -- ;
                  delete this;
                  return 0;
           }
           return  (ULONG) m_Ref;
    }
    HRESULT CA::NondelegationQueryInterface(const IID& iid, void **ppv)
    {
           if ( iid == IID_IUnknown )
           {
                  *ppv = (INondelegatingUnknown *) this ;
                  ((IUnknown *)(*ppv))->AddRef() ; // 这里其实是调用NonDelegationAddRef()!!!!
           } else if ( iid == IID_SomeInterface )
           {
                  *ppv = (ISomeInterface *) this ;
                  ((ISomeInterface *)(*ppv))->AddRef() ; // 而这里则不然,这里直接调用了AddRef(),
                      // 如果是聚合状态调用外部Compoent的Addref,否则则调用NonDelegationAddRef!!!wink_smile.gif
           }
           else
           {
                  *ppv = NULL;
                  return E_NOINTERFACE ;
           }
           return S_OK;
    }
    ULONG CA::AddRef ()
    {
           if  ( m_pUnknownOuter != NULL )
                  return m_pUnknownOuter->AddRef();
           else
                  return NondelegatingAddRef();
    }
    ULONG CA::Release ()
    {
           if  ( m_pUnknownOuter != NULL )
                  return m_pUnknownOuter->Release ();
           else
                  return NondelegationRelease();
    }
    HRESULT CA::QueryInterface(const IID& iid, void **ppv)
    {
           if  ( m_pUnknownOuter != NULL )
                  return m_pUnknownOuter->QueryInterface(iid, ppv);
           else
                  return NondelegationQueryInterface(iid, ppv);
    }
    HRESULT CA::SomeFunction()
    {
           printf("This is CA::SomeFunction!/n");
           return S_OK;
    }
    由上面的代码可以看出,被聚合的对象需要实现两个IUnknown接口Delegation Unknown和NonDelegation Unknown接口NonDelegation Unknown是按正常方式实现的IUnknown接口。Delegation Unknown在非Aggregation使用时候直接把所有调用传给NonDelegation Unknown接口;而在Aggregation下,它把调用传给外部对象的接口,而此时外部对象通过NonDelegation接口对内部对象进行控制
    Aggregation下CAFactory的CreateInstance实现:
    HRESULT CAFactory::CreateInstance(IUnknown *pUnknownOuter, const IID& iid, void **ppv)
    {
           HRESULT hr;
           //  iid must be IID_IUnknown for aggregating
           if ( ( pUnknownOuter != NULL ) && ( iid != IID_IUnknown ) )
           {            return CLASS_E_NOAGGREGATION;       }
           *ppv=NULL;
           hr=E_OUTOFMEMORY;
           //Create the object passing function to notify on destruction.
           CA *pObj=new CA (pUnknownOuter);
           if (NULL==pObj)          return hr;  
           //Obtain the first interface pointer (which does an AddRef)
           hr = pObj->NondelegationQueryInterface(iid, ppv);
        if (hr != S_OK) {
                 //Kill the object if initial creation or FInit failed.
                  g_CompANumber --; // Reference count g_CompANumber be added in constructor
                  delete pObj;
           }
           return hr;  
    }
  5. MFC的COM Aggregation实现:COM使用了C++嵌套类来实现COM接口,并且使用接口映射表来简化编程工作,MFC对COM的支持是从类CCmdTarget开始。
    #define DECLARE_INTERFACE_MAP() /
    private: /
         static const AFX_INTERFACEMAP_ENTRY _interfaceEntries[]; /
    protected: /
         static const AFX_INTERFACEMAP interfaceMap; /
         static const AFX_INTERFACEMAP* PASCAL GetThisInterfaceMap(); /
         virtual const AFX_INTERFACEMAP* GetInterfaceMap() const; /
    struct AFX_INTERFACEMAP_ENTRY
    {
         const void* piid;       // the interface id (IID) (NULL for aggregate)
         size_t nOffset;         // offset of the interface vtable from m_unknown
    };
    struct AFX_INTERFACEMAP
    {
    #ifdef _AFXDLL
         const AFX_INTERFACEMAP* (PASCAL* pfnGetBaseMap)(); // NULL is root class
    #else
         const AFX_INTERFACEMAP* pBaseMap;
    #endif
         const AFX_INTERFACEMAP_ENTRY* pEntry; // map for this class
    };
    由此可以很明显看出,MFC继续使用Map表来实现COM接口。查看具体的Map表的增加和删除宏可以更详细的了解架构。
    #define BEGIN_INTERFACE_MAP(theClass, theBase) /
         const AFX_INTERFACEMAP* PASCAL theClass::GetThisInterfaceMap() /
             { return &theClass::interfaceMap; } /
         const AFX_INTERFACEMAP* theClass::GetInterfaceMap() const /
             { return &theClass::interfaceMap; } /
         AFX_COMDAT const AFX_INTERFACEMAP theClass::interfaceMap = /
             { &theBase::GetThisInterfaceMap, &theClass::_interfaceEntries[0], }; /
         AFX_COMDAT const AFX_INTERFACEMAP_ENTRY theClass::_interfaceEntries[] = /
         { /
    #define INTERFACE_PART(theClass, iid, localClass) /
    { &iid, offsetof(theClass, m_x##localClass) }, /
    #define INTERFACE_AGGREGATE(theClass, theAggr)
    { NULL, offsetof(theClass, theAggr) }, /
    #define END_INTERFACE_MAP() /
    { NULL, (size_t)-1 } /
    }; /
    其中,offsetof宏可以给出成员变量与分类之间的偏移量,编译器在编译时候计算这个常数。
    而接口部分定义则使用宏BEGIN_INTERFACE_PARTINIT_INTERFACE_PARTEND_INTERFACE_PART进行定义。
    #define BEGIN_INTERFACE_PART(localClass, baseClass) /
         class X##localClass : public baseClass /
         { /
         public: /
             STDMETHOD_(ULONG, AddRef)(); /
             STDMETHOD_(ULONG, Release)(); /
             STDMETHOD(QueryInterface)(REFIID iid, LPVOID* ppvObj); /
    #define INIT_INTERFACE_PART(theClass, localClass) /
             size_t m_nOffset; /
             INIT_INTERFACE_PART_DERIVE(theClass, localClass) /
    #define INIT_INTERFACE_PART_DERIVE(theClass, localClass) /
             X##localClass() /
                  { m_nOffset = offsetof(theClass, m_x##localClass); } /
    #define END_INTERFACE_PART(localClass) /
         } m_x##localClass; /
         friend class X##localClass; /
  6. 复习二将重点涉及COM一些高级概念,从MarshalThread Model(Apartment和Free)。

组合/聚合复用原则(Composition/Aggregation Principle)

定义 又叫合成复用原则。原则就是在一个新的对象里面通过关联关系(包括组合关系和聚合关系)使用一些已有的对象,使之成为新对象的一部分,新对象通过委派调用已有对象的方法达到复用其已有功能的目的。也就是,...

COM--可重用性(包容和聚合)

面向对象系统的3个最基本特征是封装性、多态性、重用性。 所谓的重用性是指,当一个程序单元能够对其他的程序单元提供功能服务是,尽可能的重用原先程序单元的代码,既可以在源代码一级重用,也可以在执行代码一...

COM技术内幕学习笔记---第八章---组件复用:包容和聚合

COM 不支持实现继承的原因在于这种继承方式将 使得一个对象的实现同另外一个对象的实现紧紧地关联起来。 在这种情况下,当基类的实现被修改之后,派生类将无法正常运行而必须被修改。对于一个中等规模的C+...

学习MongoDB 十一: MongoDB聚合(Aggregation Pipeline基础篇上)(三)

db.collection.aggregate()是基于数据处理的聚合管道,每个文档通过一个由多个阶段(stage)组成的管道,可以对每个节点的管道进行分组、过滤等功能,然后经过一系列的处理,输出相应...

monodb 聚合框架 Aggregation

前提:本人采用mongodb和spring整合的project
  • tzwjava
  • tzwjava
  • 2014年10月29日 09:46
  • 439

MongoDB 聚合管道(一)(Aggregation Pipeline)

详细介绍了MongoDB中聚合管道Pipeline的使用。

组合与聚合的选用 (Composition & Aggregation)

看到不少朋友讨论组合与聚合的异同,我觉得有两个要点决定了组合与聚合的选用: 共享性 组合中各个子件是被宿主独占使用,实例间不存在共享同一个子件。 ...

《Microsoft SQL Server 2008 Analysis Services Step by Step》学习笔记十四:设计聚合(Aggregation)(上)

SQL Server 2008中SQL应用系列及BI笔记系列--目录索引导读:本文介绍Analysis Services中与聚合(Aggregations)相关的设计。本文将包括以下内容:■1、使用A...

UML中关联(Association)、聚合(Aggregation)和合成(Composition)之间的区别

现在,我们需要设计一个项目管理系统,目前我们收集到了如下这些需求: REQ1:一个项目内有多名项目成员REQ2:一名项目成员只能被指派给一个项目REQ3:一个项目内仅有一名项目成员被指派为项目经...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:COM复用的中Containment(包容)和Aggregation(聚合)的实现
举报原因:
原因补充:

(最多只允许输入30个字)