Overview
The technical problem is that the current project requires an abstract factory for the working class of the C ++ template, which, as far as I can tell, is impossible. Thus, I need an alternative solution to prevent clients from hanging on the details of the employee and worker from any particular client environment.
Customization
I have a Worker class that internally requires a container class C to remember process information. Processing information is organized into a BufferType structure, so Worker interacts internally with a member of type C< BufferType > . On the other hand, we do not want Worker clients to know about Worker::BufferType , which reflect irrelevant information about the use of the Worker API, which may change over time.
The situation is complicated by the fact that C is an abstract class that has various implementations of container functionality depending on the actual environment (for example, a database). Obviously, we donβt want Worker know about this, it should work in any environment for which there is a C implementation.
Since I don't have much experience writing factories, I went ahead and wrote the following:
These are the containers I have to deal with:
template <class T> class C { // container interface }; template <class T> class CImpl : public C<T> { // implements C interface };
Here's how I would like to implement the Worker class:
class Worker { public: Worker( AbstractCFactory& f ) : _f( &f ), _buffer( NULL ) {} void doSomething() { _buffer = _f->create<BufferType>( );
However, this will require something like the following factories:
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 >(); } };
While I thought this was a great design, the compiler was not so enthusiastic and reminded me that template methods cannot be virtual. Now, when I think about it, it makes sense - the compiler cannot know what code should be generated for the template method in the factory if the factory type is determined only at runtime.
Ugly workaround
First, I implemented factories as templates to allow the create() virtual function:
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 >(); } };
Then I moved BufferType to the Worker public interface, allowing the client to instantiate ConcreteCFactory< Worker::BufferType > to pass to the Worker constructor.
class Worker { public: typedef struct { int someInfo; } BufferType; Worker( AbstractCFactory< BufferType >& f ) : _f( &f ), _buffer( NULL ) {} void doSomething() { _buffer = _f->create( );
Obviously, my solution is not a real solution, because it still introduces an undesirable client dependency on the private details of the Worker ( BufferType ) implementation, exposing them to the public interface.
Question
Is there a right solution that doesn't make me break encapsulation i.e. does not support Worker independent of CImpl , and the client is not dependent on Worker::BufferType ?