Sign in to follow this  
Peter_APIIT

Abstract Factory Pattern Advice

Recommended Posts

Hello to all, i would like to create a family of object at run time rather than hard coded in main. My situation is like this. ObjectFactory(Abstract) inherits by three classes which are AdminOF, HumanPersonnelOF and StaffOF. Moreover, there are another hierarchy which its interface is concretePosition which inherits by three classes which are Admin, HumanPersonnel and Staff. I would like to create the object based on their user name when login in the following format. Admin - A0000 HumanPersonnel - H0000 Staff - S0000 Then, they can access their particular function which have option menu. Please advise. Thanks. EDIT: If username[0] == 'A' then create Administrator object at run time else if usernmae[0] = 'H' then create HUMANPersonnel object else if username[0] == 'S' then create Staff. I want something like this but i don't want the if statement but i need them in two class hierarchy with polymorphism. That's means i receive something in abstract base class and call the actual type of derived class creator. Last time, i wrote something similar but using template argument fixed it at compile time. Please advise. Here is my code. Code: class objectFactory { public: objectFactory(); void createInstance() = 0; ~objectFactory(); }; class AdministratorFactory : public objectFactory { public: void createInstance(); }; class HRFactory : public objectFactory { public: void createInstance(); }; class StaffFactory : public objectFactory { public: void createInstance(); }; class usernameType { private: login loginSession; } I could find any mechanism to determine usernameType and call the appropriate createInstance(). class login contains a std::string username and password. There are two approaches in my head right now. 1. Without polymorphism 2. With polymorphism 1. I can just create the object using if statement such as Code: if login.username == 'A" AdministratorFactory instance; instance.createInstance(); else if login.username == 'H' HRFactory instance; instance.createInstance(); else if login.username == 'S' StaffFactory instance; instance.createInstance(); I could write this if statement using template too but i would like to master C++ polymorphism. 2. The difficulties of this approach is to construct the appropriate type based on the username. If the login.username is 'A' then create AdminUserType and its member function will called createInstance() to the appropriate type. This is my question How to construct usernameType based on login.username and forward the request to createInstance() method. I really need your help. Thanks for your help.

Share this post


Link to post
Share on other sites
I think you misunderstand the factory pattern, which has two main features: it hides details of the creation (perhaps constructor parameters which are not taken explicitly from client code, but are instead indirectly determined by how other parts of the system are configured), or to create one of several concrete derivations of a base class to be created according to some set of rules.

You are attempting to use the later feature -- that is, you want one concrete derivation of concretePosition to be created by a factory based on the rule that the first character in a string determines the concrete type.

The if statement (or some equivilent) is unavoidable -- a decision must be made, after all. However, the client code should not be responsible for determining which Factory to call -- if the client code must determine this anyhow, then there is no advantage to the factory pattern over simply calling the derived types constructor (unless it is also hiding construction details.)

What you really seem to want is a single factory for the concretePosition class of objects. If you think about it, this factory function maps an input string to one of the derived types. Therefore, what you need is a function which determines the concrete type based on this string, creates a new instance of that concrete type, and then returns it through a pointer to its base class. This Factory can be combined with per-concrete-class factories for each of the derived types if additional construction details are hidden.

Share this post


Link to post
Share on other sites
abstract factory example
I have another example which looks at an abstract factory in which the type constructors take parameters, yet I have not created a page for it. It involves using type lists as detailed in book listed on the above page.

Share this post


Link to post
Share on other sites
What you probably want is a virtual constructor.

A virtual constructor is a class that returns a pointer to the base class, and based on it's arguments decides which derived class it actually allocates and returns.

...

Factories are objects that are (in the pattern sense) functions from (creation arguments) to (created objects). The code you wrote ... doesn't look like such a function. Note that creation arguements can be empty.

Something along the lines of:

class objectFactory
{
public:
concretePosition* createPosition( std::string userName );
}


Now your client code just does this:

void do_stuff( objectFactory* factory, std::string userName )
{
[...]
concretePosition* positionInstance = factory->createPosition( userName );
[...]
}

You create a run-time instance of the position object. The createPosition function has the if/switch statement in it that distinguishes between Admin, HumanPersonnel, and Staff.

Now, you can use the "there are multiple factories" approach, but that should ideally be hidden behind a single run-time interface. (The details of what exact factory creates which exact concretePosition for a given userName probably shouldn't be exposed to the client code).

...

Now you can do this with static polymorphism (via template code or the like), but you end up having to do the runtime->static mapping via an explicit if/switch statement at some point.

Share this post


Link to post
Share on other sites
KISS - why don't you want to keep the if statements? Alternatively, if you were going to end up with lots of codes defining classes, you could map codes to prototypes.

Share this post


Link to post
Share on other sites
Quote:

The if statement (or some equivilent) is unavoidable -- a decision must be made, after all. However, the client code should not be responsible for determining which Factory to call -- if the client code must determine this anyhow, then there is no advantage to the factory pattern over simply calling the derived types constructor (unless it is also hiding construction details.)


Yes, some decision must be made upon creation process. Yes, the client code(class Admin, staff or HR) should not determine which factory to call. I wrapps their username in class called usernameType, ten based on the type called object factory. I still didn't directly ask client to call object factory.

How abstract factory hides construction details ?


Quote:

What you really seem to want is a single factory for the concretePosition class of objects. If you think about it, this factory function maps an input string to one of the derived types. Therefore, what you need is a function which determines the concrete type based on this string, creates a new instance of that concrete type, and then returns it through a pointer to its base class. This Factory can be combined with per-concrete-class factories for each of the derived types if additional construction details are hidden.


Yes, i quite agree. A function used to determine/map which concrete usernameType to forward the creation to object Factory. I not really understand here.

I bag your pardon since English is not my primary language.

I get suggestion in google usenet group.


class UserCreator
{
public:
bool registerUserFactory(const std::string& name, std::auto_ptr<objectFactory> f)
{
return m_creator.insert(name, boost::shared_ptr<objectFactory>(f.release())).second;
}

void createUser(const std::string& name)
{
// this method shoud return something different than "void",but I'm not sure what the
// objectFactory::createInstance method should return

assert(m_creator.find(name) != m_creator.end());
// or return some error in that case
return m_creator.find(name).second->createInstance();
}

private:
typedef std::map< std::string, boost::shared_ptr<objectFactory> > UserCreator;
UserCreator m_creator;

UserCreator uc;
uc.registerUserFactory("Admin", std::auto_ptr<objectFactory>(new
AdministratorFactory));
uc.registerUserFactory("HumanPersonel", std::auto_ptr<objectFactory>
(new HRFactory));
uc.registerUserFactory("Staff", std::auto_ptr<objectFactory>(new
StaffFactory));

// and now to create the appropriate user, you can just type the following:
uc.createUser(login.username)




I don't know whether this is what you mean.


Quote:

KISS - why don't you want to keep the if statements? Alternatively, if you were going to end up with lots of codes defining classes, you could map codes to prototypes.


The reason is i would like learn abstract factory and use OOP if replacement. Second, i need to develop a program that maintainable since if i add another derived class, i also need to add another if statement.

Why create a lot of classes will end up with prototypes ?


Thanks for your explanation.


EDIT:

My solution is like this. Basically, there are two hierarchy which are ObjecFactory which have three derived classes which are AdminFactory, HRFactory and StaffFactory. Another class hierarchy is wraps login session inside usernameType which have three derived classes also same as above.

I was thinking the difficulties in creating concrete usernameType then forward to concrete objectFactory to create the object. Now, i have solution which is using factory method in usernameType hierarchy. Is this possible ?

Thanks.

[Edited by - Peter_APIIT on June 24, 2009 5:44:19 AM]

Share this post


Link to post
Share on other sites
The alternative to a if-then-else would be static polymorphism in this case.
http://www.chips.navy.mil/archives/99_oct/polymorphism.htm

you could do a template as "template<char N> stuff" and then specialize it:
template<'A'> stuff(std::string){...}
template<'H'> stuff(std::string){...}
etc...

Never tried char my self but I know that int works.

If you want dynamic polymorphism you have to use a if-then-else or switch.
Or you can use a collection(hastable<char,factory>) of instances which you populate on run time.

Generally polymorphism is based on types not values and you are looking to combine the two.

Share this post


Link to post
Share on other sites
Well, why would a collection not be suitable?
Basically, you'd initialize the collection with the appropriate factory for each string, i.e.

map.put('A', <factoryA>);
map.put('B', <factoryB>);
...

Then you'd just retrieve the factory by map.get(username[0]).

One advantage of that approach would be that you're able to add more factories at runtime.

However, like Ravyne said, the client should not know about the concrete factories.
Instead it might know about a meta factory (or factory method), i.e. a factory that knows how to parse the user name and calls the appropriate concrete factory.

Then you would get something like this (heavily simplified):


//in your login code
User user = metaFactory.create(username);

...

class MetaFactory
{
private:
map<char, conreteFactory> factories;

public:
User create(string username, /*more construction args*/)
{
return factories.get(username[0]).create(/*construction args, e.g. username*/);
}
}


Share this post


Link to post
Share on other sites
Quote:
Original post by Peter_APIIT
How abstract factory hides construction details ?


Say X is the information needed to decide which class to instantiate.

Instead of interpreting X yourself, you pass X to the abstract factory, and the abstract factory interprets X. The construction details are "hidden" in that they are encapsulated in the factory.

Quote:

I get suggestion in google usenet group.


void createUser(const std::string& name)
{
// this method shoud return something different than "void",but I'm not sure what the
// objectFactory::createInstance method should return



It should return a shared_ptr to whatever is the base class of the things created by the factory.

Quote:
I don't know whether this is what you mean.


This is one common approach, yes.


Quote:

Why create a lot of classes will end up with prototypes ?


He said, if you have a lot of codes ("Admin", "Staff" etc.), then you can use prototypes to avoid writing out all the if-statements. That's basically what the other code you suggested does: each UserFactory does the work of a prototype.

With the actual prototype approach, you give the base User class a virtual 'clone' function, which makes a shared_ptr to a new copy of the object. That way, you put Users into your map instead of UserFactories, and call clone() instead of createInstance().

Share this post


Link to post
Share on other sites
Quote:

He said, if you have a lot of codes ("Admin", "Staff" etc.), then you can use prototypes to avoid writing out all the if-statements. That's basically what the other code you suggested does: each UserFactory does the work of a prototype.

With the actual prototype approach, you give the base User class a virtual 'clone' function, which makes a shared_ptr to a new copy of the object. That way, you put Users into your map instead of UserFactories, and call clone() instead of createInstance().


I probably understand the statement. Since there are many factory that have same state. Hence, we can use prototype to clone it.

Am i correct ?
Quote:

My solution is like this. Basically, there are two hierarchy which are ObjecFactory which have three derived classes which are AdminFactory, HRFactory and StaffFactory. Another class hierarchy is wraps login session inside usernameType which have three derived classes also same as above.

I was thinking the difficulties in creating concrete usernameType then forward to concrete objectFactory to create the object. Now, i have solution which is using factory method in usernameType hierarchy. Is this possible ?

Thanks.

Let concentrated back to my problem where i have a solution but i need expert advice.

Share this post


Link to post
Share on other sites
This is my question.

My solution is like this. Basically, there are two hierarchy which are ObjecFactory which have three derived classes which are AdminFactory, HRFactory and StaffFactory. Another class hierarchy is wraps login session inside usernameType which have three derived classes also same as above.

I was thinking the difficulties in creating concrete usernameType then forward to concrete objectFactory to create the object. Now, i have solution which is using factory method in usernameType hierarchy. Is this possible ?

My class hierarchy is like this.



objectFactory
|
AdminFactory HRFactory StaffFactory


usernameType (Contain reference to login)
|
AdminType HRType Stafftype (Forward call to concrete factory)

class login;

Human
|
Admin Hr Staff


Thanks.

Share this post


Link to post
Share on other sites
What do AdminFactory, HRFactory and StaffFactory do when creating the object? ie do they just call the constructor for the object(or clone method on an instance) or do something more substantial?
Using the code from the page I linked to


typedef Human User_type;
typedef Abstract_factory<User_type,std::string> User_factory;

int main()
{
User_factory factory;
factory.register_key<Admin>("admin");
factory.register_key<Hr>("hr");
factory.register_key<Staff>("staff");

//get key a login type
std::string key;
...
User_type* user( factory.create(key).release());
}

Share this post


Link to post
Share on other sites
Quote:
What do AdminFactory, HRFactory and StaffFactory do when creating the object? ie do they just call the constructor for the object



It just called the constructor to dynamic allocate memory.

Actually, i have coded the class hierarchy but i want to learn your approach too.

What approach the code you using ?

Thanks.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this