c – 模板类困境的抽象工厂
概观
技术问题是当前的设计似乎需要一个C模板工作者类的抽象工厂,据我所知,这是不可能的.因此,我需要一种替代解决方案来防止客户端依赖于工作者的实现细节以及来自任何特定客户端环境的工作者. 那个设定 我有一个Worker类,内部需要一个容器类C来记忆处理信息.处理信息在BufferType结构中组织,因此Worker内部处理类型为C<的成员. BufferType>.另一方面,我们不希望Worker的客户端知道Worker :: BufferType,它反映了可能随时间变化的与Worker无关的实现细节. 由于C是一个抽象类,根据实际环境(例如数据库)具有不同的容器功能实现,因此情况变得复杂.显然,我们不希望Worker知道这一点,它应该在任何有C实现的环境中工作. 由于我在编写工厂方面没有那么多经验,所以我继续编写以下内容: 这些是我必须处理的容器: template <class T> class C { // container interface }; template <class T> class CImpl : public C<T> { // implements C's interface }; 这就是我想要实现Worker类的方式: class Worker { public: Worker( AbstractCFactory& f ) : _f( &f ),_buffer( NULL ) {} void doSomething() { _buffer = _f->create<BufferType>( ); // ... do something with _buffer } private: AbstractCFactory* _f; typedef struct { int someInfo; } BufferType; C< BufferType >* _buffer; }; 但是,就工厂而言,这需要以下内容: class AbstractCFactory { public: template <class T> virtual C< T >* create() = 0; }; class ConcreteCFactory : public AbstractCFactory { public: template <class T> virtual C< T >* create() { return new CImpl< T >(); } }; 虽然我认为这是一个很棒的设计,但编译器并不那么热情,并提醒我模板方法不能是虚拟的.现在我考虑一下,这是有道理的 – 如果工厂类型仅在运行时确定,则编译器无法知道在工厂中为模板方法生成哪些代码. 丑陋的解决方法 首先,我将工厂实现为模板以允许虚拟的create()函数: template <class T> class AbstractCFactory { public: virtual C< T >* create() = 0; }; template <class T> class ConcreteCFactory : public AbstractCFactory { public: virtual C< T >* create() { return new CImpl< T >(); } }; 然后,我将BufferType移动到Worker的公共接口,允许客户端创建一个ConcreteCFactory< Worker :: BufferType>要传递给Worker的构造函数的实例. class Worker { public: typedef struct { int someInfo; } BufferType; Worker( AbstractCFactory< BufferType >& f ) : _f( &f ),_buffer( NULL ) {} void doSomething() { _buffer = _f->create( ); // ... do something with _buffer } private: AbstractCFactory< BufferType >* _f; C< BufferType >* _buffer; }; 显然,我的解决方法不是一个真正的解决方案,因为它仍然通过将它们暴露给公共接口而引入了对Worker(BufferType)的私有实现细节的不良客户端依赖. 题 是否有一个正确的解决方案,不会强迫我打破封装,即保持工人独立于CImpl和客户端独立于Worker :: BufferType? 解决方法
CImpl< T>是必须由客户端提供的模板类,它必须专门用于CImpl< BufferType>.在专业化时,必须定义CImpl和BufferType.一种可能性是要求客户端提供包含C< T>的实现的定义的CImpl.h文件:
cimpl.h(由客户提供) template <class T> class CImpl : public C<T> { // implements C's interface }; worker.h: class IC { }; template <class T> class C: public IC { // container interface }; class AbstractCFactory { public: virtual IC* create() = 0; }; class Worker { public: Worker( AbstractCFactory& f ) : _f( &f ),_buffer( 0 ) {} void doSomething(); private: AbstractCFactory* _f; C< struct BufferType >* _buffer; }; AbstractCFactory& getDefaultFactory(); worker.cpp #include "worker.h" #include "cimpl.h" #include <stdlib.h> template <class T> class ConcreteCFactory : public AbstractCFactory { public: virtual IC* create() { return new CImpl< T >(); } }; struct BufferType { int someInfo; }; void Worker::doSomething() { _buffer = static_cast<C<BufferType>*>(_f->create( )); // ... do something with _buffer } AbstractCFactory& getDefaultFactory() { static ConcreteCFactory<BufferType> f; return f; } 用法示例: #include "worker.h" ... AbstractCFactory& f = getDefaultFactory(); Worker w(f); w.doSomething(); 另一种可能性是将.h文件拆分为2个,一个公共接口和一个私有客户端永远不应该直接使用的文件. worker.h class IC { }; template <class T> class C: public IC { // container interface }; class AbstractCFactory { public: virtual IC* create() = 0; }; struct BufferType; class Worker { public: Worker( AbstractCFactory& f ) : _f( &f ),_buffer( 0 ) {} void doSomething(); private: AbstractCFactory* _f; C< struct BufferType >* _buffer; }; AbstractCFactory& getFactory(); #include "private.h" private.h: struct BufferType { int someInfo; }; template<class I> class CFactory: public AbstractCFactory { public: virtual IC* create() { return new I(); } }; template<class I> AbstractCFactory& getFactory() { static CFactory<I> fact; return fact; } worker.cpp: #include "worker.h" void Worker::doSomething() { _buffer = static_cast<C<BufferType>*>(_f->create( )); // ... do something with _buffer } 用法示例: #include "worker.h" ... template <class T> class CImpl : public C<T> { // implements C's interface }; ... AbstractCFactory& f = getFactory<CImpl<BufferType>>(); Worker w(f); w.doSomething(); (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |