Thread: Question about the Factory pattern.

  1. #1
    Registered User
    Join Date
    Oct 2006
    Location
    UK/Norway
    Posts
    485

    Question about the Factory pattern.

    Hallo, I am working on an assignment where we get extras points for using design patters. I have no real experience with design patters and I am not that experienced with programming, so I have a question about the factory patter.

    Is this correct use of the factory pattern?

    Code:
    class Object
    {
    public:
    	// List of virtual functions
    protected:
    	Object();
    };
    
    class ObjectA : public Object
    {
    public:
    	ObjectA()
    	// List of private functions
    };
    
    class ObjectB : public Object
    {
    public:
    	ObjectB()
    	// List of private functions
    };
    
    class ObjectFactory
    {
    public:
    	ObjectFactory();
    	ObjectA* createObjectA()
    	{
    		ObjectA* obj = new ObjectA();
    		return obj;
    	}
    
    	ObjectB* createObjectB();
    };
    Thanks

  2. #2
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    That's not how I'm used to seeing it. There are at least two different factory patterns that I'm aware of and use. They are concrete factory pattern and abstract factory pattern.

    There are at least two approaches that I know of. There is the case where the creator is an abstract class and does not provide an impl for the factory method it declares and there is the case where a concrete class provides the defalult impl for the method. There is also a case where the abstract could provide a default impl.

    There is also the parameterized factory method that lets a factory create multiple kinds of products. This is normally in the form of a switch in the create() method. You can also template the factory to avoid subclassing.

    I highly recommend taking a look at Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. It's available on Amazon for a good price.

  3. #3
    Registered User
    Join Date
    Oct 2006
    Location
    UK/Norway
    Posts
    485
    I have that book, but I am still having a hard time using the pattern in it. I think that I might need some more programming experience before I can really find it useful.

    Would this be a better example of a factory?

    Code:
    class ObjectFactory
    {
    public:
    	ObjectFactory();
    	ObjectA* createObjectA(const std::string *weapon = 0, const std::string *look = 0, int x = 0, int y = 0)
    	{
    		ObjectA* obj = new ObjectA();
    		
    		if(look != 0)
    		{
    			if(look == "Hansome")
    				obj->assingPicture("data//looksVeryGood.jpeg");
    			else if(look == "Dog")
    				obj->assingPicture("data//animal//dog.png");
    		}
    
    		if(weapon != 0)
    		{
    			if(weapon == "Rifle") {
    				obj->changeWeapong(enum_rifle);
    				obj->setAmmo(10);
    			}
    			else if (weapon == "Handgun")
    			{}
    		}
    
    		if(x != 0 && y != 0)
    		{
    			obj->move(x,y);
    		}
    
    		return obj;
    	}
    
    	ObjectB* createObjectB();
    };

  4. #4
    Registered User valaris's Avatar
    Join Date
    Jun 2008
    Location
    RING 0
    Posts
    507
    Indeed one of the best books I have ever read, and re-read, and then re-read again.

  5. #5
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    To simplify things I normally go with the concrete factory pattern based on the switch idea. This makes it somewhat straightforward as to what is happening at the expense of elegance.

    Once you get that working then you can move on to the more complex factory patterns. Abstract factory pattern is the most robust but also somewhat complex although not bad after you get used to it.

  6. #6
    Registered User
    Join Date
    Oct 2006
    Location
    UK/Norway
    Posts
    485
    Once you get that working then you can move on to the more complex factory patterns. Abstract factory pattern is the most robust but also somewhat complex although not bad after you get used to it.
    The problem is not to get things working, the real problem is if my problem can be solved by applying a pattern (well, in reality I dont really have a problem, I am just looking for higher marks)
    What I have is several objects that is derived from a base class thats need to be created all over my program. So I was wondering if a factory would be suitable, but from the looks of it, its not (i think)


    Is the following code a some kind of pattern at all, or is it just "code"?
    Can it be described as a Builder pattern?
    Code:
    class ObjectFactory
    {
    public:
    	ObjectFactory();
    	ObjectA* createObjectA(const std::string *weapon = 0, const std::string *look = 0, int x = 0, int y = 0)
    	{
    		ObjectA* obj = new ObjectA();
    		
    		if(look != 0)
    		{
    			if(look == "Hansome")
    				obj->assingPicture("data//looksVeryGood.jpeg");
    			else if(look == "Dog")
    				obj->assingPicture("data//animal//dog.png");
    		}
    
    		if(weapon != 0)
    		{
    			if(weapon == "Rifle") {
    				obj->changeWeapong(enum_rifle);
    				obj->setAmmo(10);
    			}
    			else if (weapon == "Handgun")
    			{}
    		}
    
    		if(x != 0 && y != 0)
    		{
    			obj->move(x,y);
    		}
    
    		return obj;
    	}
    
    	ObjectB* createObjectB();
    
    
    	// Will be used to load objects that are stored in a file
    	Object* createObject(const std::string type)
    	{
    		if(type == "objectA)
    			return createObjectA();
    		if(type == "objectB")
    			return createObjectB();
    	}
    };

  7. #7
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Isn't the question, why the constructor of ObjectA doesn't take the arguments of createObjectA, and do all the work of that function itself.

    What good is it if I have to type
    Code:
    ObjectFactory factory;
    Object* p = factory.createObjectA(long_list_of_arguments);
    
    //vs.
    
    Object* p = new ObjectA(long_list_of_arguments);
    I'd rather do something first about the long_list_of_arguments, e.g x and y might be held together in a Coordinate class/struct.

    Not sure, but isn't (one) point of the factory the use such as
    Code:
    Animal* a = factory.create("dog"); //returns new Dog
    Animal* b = factory.create("cat");  //returns new Cat
    Now the creation of objects is handled in one place, and if I add a new animal, I'd only have to modify the create() function (e.g by adding another else if) and perhaps a data file.
    If you have a different function for each subobject, you'd still have to go over all the code to add the possibility to create objects of the new type (add createObjectC calls).

    That is, a class should have some purpose...
    Last edited by anon; 11-27-2008 at 04:29 PM.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  8. #8
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    If you are going to make a create for every object the factory can create this sort of ruins the idea of a factory.


    Code:
    class IObject
    {
    };
    
    class SomeObject : public IObject
    {
    };
    
    class AnotherObject : public IObject
    {
    };
    
    enum PRODUCT_TYPES
    {
       SOME_OBJECT,
       ANOTHER_OBJECT
    };
    
    class ObjectFactory
    {
        public:
           ...
           IObject *CreateProduct(PRODUCT_TYPES object_type);
    
    };
    
    
    IObject *ObjectFactory::CreateProduct(PRODUCT_TYPES object_type)
    {
         IObject *product = 0;
         switch (object_type)
         {
              case SOME_OBJECT:
              { 
                   product = new SomeObject();
                   break;
              }
              case ANOTHER_OBJECT:
              {
                   product = new AnotherObject();
                   break;
              }
         }
         
         return product;
    }
    This is one way to do a factory. Keep in mind you could also create an abstract factory that would then factory out different objects.

    For instance if you were using Direct3D and OpenGL you would want to use an abstract factory. One impl would factory out Direct3D objects and one would factory out OpenGL objects. The interface to the factory remains the same so you could theoretically change your graphics API of choice by dropping in a new factory impl. Calls to the factory would not change at all.

    In a real system this factory would only be accessible by my resource manager since that is the only object that contains the allocated objects.
    Last edited by VirtualAce; 11-27-2008 at 04:32 PM.

  9. #9
    Registered User
    Join Date
    Oct 2006
    Location
    UK/Norway
    Posts
    485
    Ok, ill give this one more shot. What do people think about the following code? Is it more like a factory now?


    Code:
    class ObjectFactory
    {
    public:
    	ObjectFactory();
    	
    	Object* createObject(const std::string type)
    	{
    		if(type == "RifleEnemie")
    			return createRifleEnemie();
    		if(type == "RocketEnemie")
    			return createRoecketEnemie();
    	}
    
    private:
    	Object* createRifleEnemie()
    	{
    		Object * obj = new ObjectEnemie();
    		obj->setPicture("data//evilLookingPerson.jpeg");
    		obj->changeWeapong(enum_rifle);
    		obj->setAmmo(10);
    		
    		return obj;
    	}
    
    	Object* createRoecketEnemie()
    	{
    		Object * obj = new ObjectEnemie();
    		obj->setPicture("data//evilLookingPerson2.jpeg");
    		obj->changeWeapong(enum_rocketLuncher);
    		obj->setAmmo(2);
    
    		return obj;
    	}
    
    };
    Thanks for all the input so far

  10. #10
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    It is my opinion that a factory should only create a product. It should not alter the internal state of the product. It's sole responsibility is to factory out products, not set them up for usage. If you allow the factory to alter the internal state of the objects it produces then you are going to have a maintenance nightmare because you are coupling the factory to the setup of the products it creates. What if I wanted a rifle with more ammo? What if I wanted a rifle with different ammo or different type of ammo? The amount of parameters needed to correctly produce the object becomes overwhelming.
    Leave the actual setup of the product in question to the object that needs to use the product. I think by allowing the factory to setup the product for usage you are forcing the factory to do more than it really needs to.
    Last edited by VirtualAce; 11-27-2008 at 04:38 PM.

  11. #11
    Registered User
    Join Date
    Oct 2006
    Location
    UK/Norway
    Posts
    485
    If a factory should only create an object, what is the advantage of having a factory?

    How is:
    Object *myNewObject = factory.create(TYPEA);

    better then:
    Object *myNewObject = new ObjectA();

  12. #12
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    If a factory should only create an object, what is the advantage of having a factory?
    It centralizes the creation of your objects. Instead of having new's scattered across your code line you have them centralized in factories. The only difference between my code and yours is that mine requires an addition to the enum and to the create function in order to create new products. Yours requires the addition of more and more private functions. Yours also requires the factory to have intimate knowledge of the objects it creates and also means that the setup of the object is completely hard-coded. If you don't want it hard-coded then your create function is going to have to take an infinite amount of parameters to correctly setup all of the objects it creates.

    Perhaps this would work for you:

    Code:
    class IObject
    {
       public:
         ...
         virtual void CreateFromFile(const std::string &filename) = 0;
    };
    
    class SomeObject : public IObject
    {
       public:
         ...
         virtual CreateFromFile(const std::string &filename) = 0;  
    };
    
    void SomeObject::CreateFromFile(const std::string &filename)
    {
       //Create object from file
    }
    
    class ObjectFactory
    {
       public:
        ...
        virtual IObject *CreateProductFromFile(const std::string &filename);
    };
    
    IObject *ObjectFactory::CreateProductFromFile(const std::string &filename)
    {
         IObject *product = 0;
         switch (object_type)
         {
              case SOME_OBJECT:
              { 
                   product = new SomeObject();
                   break;
              }
              case ANOTHER_OBJECT:
              {
                   product = new AnotherObject();
                   break;
              }
         }
         
         if (product)
         {
             product->CreateFromFile(filename);     
         }
         
         return product;
    }
    This way each object knows how to set itself up for usage. The information is in the file. Now you simply pass in the filename of the file from which the object will pull data in order to correctly set itself up for use. The object is ready to be used and you also delegate setup to the object instead of to the factory. As long as all objects follow the interface everyone gets along quite nicely.
    Last edited by VirtualAce; 11-27-2008 at 04:49 PM.

  13. #13
    The larch
    Join Date
    May 2006
    Posts
    3,573
    The difference is that TYPEA could be a variable and doesn't have to be hard-coded, where as new ObjectA is hard-coded.

    Also the factory could return something different for TYPEA, depending on which factory you have chosen to use.

    And again, why do your objects need manipulation after they are created and before they can be used, because all the setup is really the job for the constructor?
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  14. #14
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Take this for example:


    Code:
    Texture *pTexture = OpenGLFactory.Create(TEXTURE);
    Texture *pTexture = Direct3DFactory.Create(TEXTURE);

  15. #15
    Registered User
    Join Date
    Oct 2006
    Location
    UK/Norway
    Posts
    485
    Thank you very much for your help. I think I have a good idea about how to implement it in my code now.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Visitor / Decorator Pattern
    By MarkZWEERS in forum C++ Programming
    Replies: 9
    Last Post: 05-16-2009, 11:53 AM
  2. Need comment on Factory Pattern Example
    By Bargi in forum C++ Programming
    Replies: 2
    Last Post: 07-04-2008, 05:46 AM
  3. Hmm.. Ai? Finding the pattern in number squences?
    By Zeusbwr in forum C++ Programming
    Replies: 8
    Last Post: 04-02-2005, 06:13 PM
  4. Question...
    By TechWins in forum A Brief History of Cprogramming.com
    Replies: 16
    Last Post: 07-28-2003, 09:47 PM
  5. (pattern *) pat & pattern * pat
    By siubo in forum C Programming
    Replies: 1
    Last Post: 04-08-2003, 10:03 PM