词条 | 类工厂 |
释义 | class factory(类工厂) 一个实现了IClassFactory接口的类,这允许它创建特定类的对象,也被称为COM Class Object。类工厂的作用是在COM中,客户程序必须通过类工厂(Class Factory)来完成创建COM对象的任务。 在开始介绍类工厂之前,先提一个小问题: 问题下面代码产生错误的原因是什么? class CFoolish { public: CFoolish(); ~CFoolish(); int m_count; … } int main() { CFoolish::m_count = 100; return 0; } 答案实在太明显了—— 没有创建对象就要访问类对象的非静态成员,不出错才怪! 我们辛苦地创建完一个接口,并按照标准COM的要求实现了它,使客户程序可以通过QueryInterface方法来得到对象中的接口。但是,有一个问题尚未解决,那就是,我们没有看到一行可以令COM对象在内存中实例化的代码,因此,如果此时使用这个接口,就会犯与前面所提的简单问题中同种类型的错误。并且,需要提醒大家的是,由于COM对象的复杂性(与前面所讲的引用计数一样),COM实例的创建仍然要依赖内部机制来管理,而不能像普通语言对象一样,由客户程序使用简单的new、delete来控制。 类工厂作用在COM中,客户程序必须通过类工厂(Class Factory)来完成创建COM对象的任务。 注意: 类工厂也被称为COM Class Object,可能这个叫法对理解类工厂的用途更有帮助。 为了透彻了解类工厂的运作机制,让我们看一看类工厂的定义: class IClassFactory : public IUnknown { virtual HRESULT CreateInstance(LPUNKNOWN pUnk , REFIID riid, void ** ppv) = 0 virtual HRESULT LockServer(BOOL fLock) = 0; } 首先可以得出的结论是,类工厂的实质是一个COM对象,它定义了一个IClassFactory接口,正是这个接口中的CreateInstance成员函数,对实例化COM组件起到了核心作用。 另外,根据COM规范,COM Class和类工厂是配对出现的。也就是说,只要有一个实现某一个或某几个接口的类被编写出来,若客户程序想对其进行实例化,就必须相应地实现与这个COM Class配对的类工厂。更具体地说,就是要实现IClassFactory接口。 举个实际的例子,也许会让大家更好理解—— 如果我们想要使用我们已经编写的一些类作一些事情,就必须实现类工厂。反之,客户程序将无法访问到类的接口,更不要谈调用其成员函数了。 实现现在,我们看一下应当如何为COM对象实现类工厂。 首先,进行类工厂的声明,代码如下: class CSimpleMath_ClassFactory : public IClassFactory // 声明用于实现IClassFactory接口的对象 { protected: // 用于引用计数的成员变量 long m_RefCount; public: CSimpleMath_MathClassFactory(); ~ CSimpleMath_MathClassFactory(); // 由于IClassFactory接口继承自IUnknown接口 // 所以,也继承了IUnknown接口的三个方法 HRESULT QueryInterface(REFIID, void** ); ULONG AddRef(); ULONG Release(); // IClassFactory接口本身需要实现的方法 HRESULT CreateInstance(LPUNKNOWN, REFIID, void**); HRESULT LockServer(BOOL bLock); }; 然后,具体实现的代码如下: CSimpleMath_ClassFactory:: CSimpleMath_ClassFactory () { // 对象构造时初始化引用计数为0 m_lRef = 0; } CSimpleMath_ClassFactory::~ CSimpleMath_ClassFactory () { } HRESULT CSimpleMath_ClassFactory::QueryInterface( REFIID riid, void** ppv ) { *ppv = 0; // 如果查询的接口为IUnknown或类工厂接口,则返回此实例 if ( riid == IID_IUnknown || riid == IID_ISimpleMathClassFactory ) *ppv = this; if ( *ppv ) { // 如果成功地引用到接口,则增加接口的引用计数 AddRef(); return S_OK; } return(E_NOINTERFACE); } ULONG CSimpleMath_ClassFactory::AddRef() { m_RefCount ++; return m_RefCount; } ULONG CSimpleMath_ClassFactory::Release() { m_RefCount --; // 减小引用计数 if (m_RefCount == 0 ) { // 如果引用计数减少至0,则释放之 delete this; return 0; } return m_RefCount; } // *****************************// // 用来产生COM对象的重要方法 // *****************************// HRESULT CSimpleMath_ClassFactory::CreateInstance ( LPUNKNOWN pUnkOuter, REFIID riid, void** ppvObj ) { CSimple_Math * p; // 声明指向COM Class的指针 HRESULT hr; *ppvObj = 0; // 创建COM Class的实例 p = new CSimple_Math; // 如果没有成功地创建对象,则返回错误值 if (!p) return(E_OUTOFMEMORY) // 如果得到了对象,则可以调用QueryInterface方法 hr = p->QueryInterface( riid, ppvObj ); // 如果调用失败则做好善后工作,并将最终的状态返回 if ( FAILED( hr ) ) delete p; return hr; } HRESULT CSimpleMath_ClassFactory::LockServer( BOOL bLock ) { if ( bLock ) { // 注意:g_LockedCount是COM对象中声明的一个全局计数变量 // 为了保障线程安全,需要对全局变量进行保护 InterlockedIncrement(g_LockedCount) ; } else { // 注意:g_LockedCount是COM对象中声明的一个全局计数变量 // 为了保障线程安全,需要对全局变量进行保护 InterlockedDecrement(g_LockedCount); } return S_OK; } 这样就完成了类工厂的具体实现。在整个实现代码中,最关键的部分使用粗体字进行了标注。经过这样一番精心实现之后,客户程序便可以通过实例化类工厂COM对象,进而得到类工厂的IClassFactory接口指针,然后,通过对该接口中核心方法CreateInstance的调用完成COM对象的实例化。剩下的事情不言自喻—— 尽情调用COM对象中的服务吧! |
随便看 |
百科全书收录4421916条中文百科知识,基本涵盖了大多数领域的百科知识,是一部内容开放、自由的电子版百科全书。