Improve company productivity with a Business Account.Sign Up

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 253
  • Last Modified:

factory pattern

The typical factory approach utilizes a map where the key could be a string, int etc. and the value is a pointer to a derived type.

Then there's typically a create or register method that makes the assumption you know the 'key' up front.   I'd like a factory method, however I _dont_ know the types in advance so this idea of invoking a register or create method in advance doesnt apply.  

In my case I'll be given a unsigned char array with N elements.  From the array, I'll instantiate 1 of 20 possible types.

Ignoring the array for a minute and opting instead for an unsigned type.  My Create method would be akin to

  Object* Product ( unsigned int type ) {
     if ( type == 1 ) {
       return new  DerivedType1 ;
     } else if ( type == 2 ) {
       return new DerivedType2;
    } else if ( type == 3 ) {
       return new DerivedType3
    } else if ( type == 4 ) {
       return new DerivedType4 ;
    //etc
   } else {
     //oops
   }
  }


I dont want to create 20 types in advance using the canonical factory pattern.  Need sample code showing how to approach this.
0
forums_mp
Asked:
forums_mp
1 Solution
 
ZoppoCommented:
Hi forums_mp,

IMO there's no need to create any pointers to implement a factory which does what you need. Here you can find a sample code which allows you to register classes at any time and let the factory create instances:
template <class BASE_CLASS,typename KEY>
class ClassFactory
{
public:
	typedef BASE_CLASS*(*fnpCreateDerivedType)();
	typedef std::map < KEY, fnpCreateDerivedType > tCreatorMap;

	static tCreatorMap&		Creators()
	{
		static tCreatorMap inst;
		return inst;
	}

	template < class _CLASS >
	static void RegisterClass( const KEY& type )
	{
		Creators().insert( tCreatorMap::value_type( type, &CreateDerivedType<_CLASS> ) );
	}

	template < class _CLASS > static BASE_CLASS* CreateDerivedType()
	{
		return new _CLASS;
	}

	static BASE_CLASS* CreateDerivedType( const KEY& type )
	{
		tCreatorMap::iterator it = Creators().find( type );

		if ( Creators().end() == it )
		{
			// error, not a registered index
			return NULL;
		}

		return (*it->second)();
	}
};

class Object
{
public:
	virtual ~Object() {}
};

class DerivedType1 : public Object
{
public:
	DerivedType1()
	{
		std::cout << "DerivedType1 instance created" << std::endl;
	}
};

class DerivedType2 : public Object
{
public:
	DerivedType2()
	{
		std::cout << "DerivedType2 instance created" << std::endl;
	}
};

class DerivedType3 : public Object
{
public:
	DerivedType3()
	{
		std::cout << "DerivedType3 instance created" << std::endl;
	}
};

typedef ClassFactory< Object, unsigned int > ObjectFactory;
typedef ClassFactory< Object, std::string > ObjectFactoryStr;

Object* Product( const unsigned int& type )
{
	Object* obj = ObjectFactory::CreateDerivedType( type );

	if ( NULL == obj )
	{
		std::cout << "Error: no class registered for type " << type << std::endl;
	}

	return obj;
}

Object* Product( const std::string& type )
{
	Object* obj = ObjectFactoryStr::CreateDerivedType( type );

	if ( NULL == obj )
	{
		std::cout << "Error: no class registered for type " << type << std::endl;
	}

	return obj;
}

int _tmain(int argc, _TCHAR* argv[])
{
	Object* prod1, *prod2, *prod3;

	ObjectFactory::RegisterClass< DerivedType1 >( 1 );
	ObjectFactory::RegisterClass< DerivedType2 >( 2 );

	prod1 = Product( 1 );
	prod2 = Product( 2 );
	prod3 = Product( 3 );
	ObjectFactory::RegisterClass< DerivedType3 >( 3 );
	prod3 = Product( 3 );

	ObjectFactoryStr::RegisterClass< DerivedType1 >( "type1" );
	ObjectFactoryStr::RegisterClass< DerivedType2 >( "type2" );
	prod1 = Product( "type1" );
	prod2 = Product( "type2" );
	prod3 = Product( "type3" );
	ObjectFactoryStr::RegisterClass< DerivedType3 >( "type3" );
	prod3 = Product( "type3" );

	return -1;
}

Open in new window

This sample demonstrate use of either integer or string as key. It doesn't matter where/when classes are registered, as long as they are registered the factory can create them.

Hope that helps,

ZOPPO
0
 
forums_mpAuthor Commented:
	ObjectFactory::RegisterClass< DerivedType1 >( 1 );
	ObjectFactory::RegisterClass< DerivedType2 >( 2 );

Open in new window


This is precisely what I dont want.  I don't want to register DerivedTypesN with a value in advance.   I'm given a 'character' array from which to determine DerivedType.  I'm starting to think I could do without a factory.   Perhaps something akin to the following might work for me.

BaseType *ptrX = ObjectFactory::DetermineDerivedType (  Array /*simulate within an int for simplicity*/ );  
ptrX->doWork ( .... )

Open in new window


Within the Determine method I may end up receving DerivedType1 or DerivedType2 or ...DeterivedTypeN
0
 
peprCommented:
You can convert any decision proces into (say) type number -- as shown by ZOPPO. Your DetermineDerrivedType(x) can be created on the top of it.

The class-factory pattern means that the object of certain class is created based on the problem context. However, the classes have to be known in advance (at least in C++). Then determining the type number is a reasonable step to be used in decision process. Whatever complexity the decision process has, you have to finally decide the target type.
0
 
sarabandeCommented:
i would like to support the answers of Zoppo and pepr. if you look at the initial if/else if "switch" of your initial post  you easily could see that calling appropriate "registering" function from a static function before would not add more or less functionality to the factory than it would with your create function.

static initialization however could register entries independently and automatically which makes the factory work bottom-up rather than top-down. that actually is the top argummment for the factory pattern that it could be advanced by any derived class with out changing the factory code or the baseclass. note if you registering function would return a bool for success you could use a static initialization for a dertived class like

// derived.h
...
class Derived : public Base
{
     static bool isregistered;
     ...
public:
     virtual Base* create() { return new Derived(); }
     ....
};

// derived.cpp
bool Derived::isregistered = BaseFactory::registerClass("Derived", new Derived());

Open in new window


(the above sample uses the class name for key and a sample pointer of the derived class to virtually create new instances).

note if your main purpose for creating pointers is the task to parse strings or messages for different inputs, a factory is not the right pattern. if the parsing has found a supported type you could also create an appropriate pointer at this point. there is no need for a factory to make things more complex as they have to be.

Sara
0
 
ZoppoCommented:
Maybe my sample wasn't well chosen, it just did the same as the original code. But there's a difference, the shown code can even register classes with keys generated at runtime, i.e.:
if ( <any condition > )
{
	ObjectFactory::RegisterClass< DerivedType1 >( 1 );
}
else
{
	ObjectFactory::RegisterClass< DerivedType2 >( 1 );
}

Open in new window

or
int i = 0;
ObjectFactory::RegisterClass< DerivedType1 >( ++i );
if ( <any condition > )
{
	ObjectFactory::RegisterClass< DerivedType2 >( ++i );
}
ObjectFactory::RegisterClass< DerivedType3 >( ++i );

Open in new window

Another sample could be reading strings as keys from a file or someting.

ZOPPO
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now