Abstract Factory Pattern Advice

Started by
16 comments, last by Peter_APIIT 14 years, 9 months ago
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.
Advertisement
I believe there are certain policies against doing homework here.
This is not a homework but a self learning exercise by myself.

Thanks.
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.

throw table_exception("(? ???)? ? ???");

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.
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.

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.
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>(newAdministratorFactory));uc.registerUserFactory("HumanPersonel", std::auto_ptr<objectFactory>(new HRFactory));uc.registerUserFactory("Staff", std::auto_ptr<objectFactory>(newStaffFactory));// 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]
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.
Static polymorphism and collection of object is not suitable since i only have one user per login session.

This topic is closed to new replies.

Advertisement