Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I found a definition of the factory design pattern as: "Define an interface for creating an object, but let the subclasses decide which class to instantiate." I understood the first part "defining interface for creation an object", but I am not able to understand the second part of "let subclasses decide which class to instantiate".

Is the following example a correct implementation of factory design pattern? If yes, please help to me to understand second part of definition with respect to the example.

        #include <iostream>
    using namespace std;

    enum genre_e{ROCK,POP, REGGAE, INVALID};

    /*Base Class*/
    class Music {
    public:
     virtual void song() = 0;
    };

    /*Derived class Rock from Music*/
    class Rock: public Music
    {
    public:
     void song()
     {
      cout<<"Nirvana: Smells like a teen spirit\n";
     }
    };

    /*Derived class Pop from Music*/
    class Pop: public Music
    {
    public:
     void song()
     {
      cout<<"Michael Jackson: Billie Jean\n";
     }
    };

    /*Derived class Reggae from Music*/
    class Reggae: public Music
    {
    public:
     void song()
     {
      cout<<"Bob Marley: No woman, No cry\n";
     }
    };

    /*Factory Class*/
    class MusicFactory
    {
    public:
     /*Factory Method*/
     Music *getMusic(genre_e genre)
     {
      Music *music = NULL;

      /*Logic based on Genre*/
      switch(genre)
      {
      case ROCK:
       music = new Rock();
       break;
      case POP:
       music = new Pop();
       break;
      case REGGAE:
       music = new Reggae();
       break;
      default:
       music = NULL;
       break;
      }
      return music;
     }
    };

    int main()
    {
     /*Create factory*/
     MusicFactory *musicFactory = new MusicFactory();

     /*Factory instantiating an object of type ROCK*/
     Music *music = musicFactory->getMusic(ROCK);

     cout<<"Song: ";
     if(music)
      music->song();
     else
      cout<<"Wrong selection dude/dudette !!";
    }
share|improve this question

2 Answers 2

You have implemented is a factory pattern.

What you describe in the first paragraph is an Abstract factory pattern. Slightly different.

An abstract factory allows you to plug in one of multiple different factory's in at run-time to get different situations.

As a big note. Stop using pointers like that. That is a complete no no in C++

  1. Do you need to create the factory dynamically.
    A local object will probably do.

  2. Even though the factory probably needs to create the objects dynamically you don't want to return pointers (but rather a smart pointer or a reference depending on how you want to handle ownership semantics (there are several good articles on SO about this so go have a read)).

Example:

class MusicFactory
{
    public:
        virtual std::unique_ptr<Music> getMusic(genre_e genre) = 0;
};

class AsianMusicFactory: public MusicFactory
{
    public:
        virtual std::unique_ptr<Music> getMusic(genre_e genre);
};
class AfricanMusicFactory: public MusicFactory
{
    public:
        virtual std::unique_ptr<Music> getMusic(genre_e genre);
};
class EuropeanMusicFactory: public MusicFactory
{
    public:
        virtual std::unique_ptr<Music> getMusic(genre_e genre);
};
class SouthAmericannMusicFactory: public MusicFactory
{
    public:
        virtual std::unique_ptr<Music> getMusic(genre_e genre);
};
class NorthAmericannMusicFactory: public MusicFactory
{
    public:
        virtual std::unique_ptr<Music> getMusic(genre_e genre);
};
// Special factory used when running unit tests.
class UnitTestMusicFactory: public MusicFactory
{
    public:
        virtual std::unique_ptr<Music> getMusic(genre_e genre);
};

So you have a bunch of different factories that all implement the same interface. But how do you know which one you should use. A common way is for a single creation point. Just ask the system it will create one for the lifetime of the application.

MusicFactory& getMusicFactory()
{
     // Note the static here.
     // It will only be created and initialized once (on first call).
     static std::unique_ptr<MusicFactory>  factory = createMusicFactory();
     return *factory;
}
// Never call this method directly.
// This function should only be called by getMusicFactory().
std::unique_ptr<MusicFactory> createMusicFactory()
{
     // Get info from user configuration.
     // Command line arguments. IP information etc whatever helps you
     // Make the decision on the actual factory that should be instantiated.
     // So we can decide what factory should be used by the application.
     std::unique_ptr<MusicFactory>  result(new XXXXX);
     return result;
}

int main()
{
    // Get the factory.
    MusicFactory&          fac   = getMusicFactory();

    // Use the factory to create the music.
    // At compile time we don't know what continents the music is from
    // as this is decided at run-time by he system and what factory is
    // created.
    std::unique_ptr<Music> music = fac.getMusic(ROCK);

    cout<<"Song: ";
    music->song();   // Should test for NULL
}
share|improve this answer
    
but in one of the discussion Don Roby is stated the definition for factroy design pattern as what i have mentioned above. please see the link stackoverflow.com/questions/4209791/…. Could some one please help me to understand correctly. –  user3665615 2 days ago
    

Yes, this is a good example of a concrete factory design pattern. In essence, in C++, what we strive to do when we create an Object factory class is to be able to pass some piece of dynamic information (a type identifier) and create a class of appropriate static type from this.

So in general, in your factory, you will have some Create function which accepts a parameter which can be used as a type identifier and returns a pointer to a base class. For instance, we might have a CShapeFactory which has the following Create method:

CShape* CShapeFactory::Create( std::string szShapeName )
{
     if( szShapeName == "Line" )
     {
         return new CLine;
     }
     else if( szShapeName == "Square" )
     {
         return new CSquare;
     }
     else
     {
         throw std::invalid_argument( "Unknown argument passed to Shape Factory Create() method" );
     }
}

You see here we are dynamically creating a different derived class based on run-time information, this is useful in circumstances when the user is often performing actions which require the creation of different related classes (i.e. a Document Manager for instance).

The other main type of factory design pattern is the Abstract design pattern, which is what you describe. This is where your factory class is an abstract implementation and you derive other factory classes from it, allowing for a further level of dynamic choice in your application. For instance, we could create the following abstract interface:

class IShapeFactory {
public:
      virtual CShape* Create( std::string szShapeName ) = 0;
};

And then implement the following two derived factory classes:

class CNormalShapeFactory : public IShapeFactory {
public:
      CShape* Create( std::string szShapeName ) {
           if( szShapeName == "Line" )
           {
               return new CLine;
           }
           else if( szShapeName == "Square" )
           {
               return new CSquare;
           }
           else
           {
               throw std::invalid_argument( "Unknown argument passed to Shape Factory Create() method" );
           }
      }
};

class CMagicShapeFactory : public IShapeFactory {
public:
      CShape* Create( std::string szShapeName ) {
           if( szShapeName == "Line" )
           {
               return new CMagicLine;
           }
           else if( szShapeName == "Square" )
           {
               return new CMagicSquare;
           }
           else
           {
               throw std::invalid_argument( "Unknown argument passed to Shape Factory Create() method" );
           }
      }
};

An application of this would be if you had a user option which determined if they wanted to create magic shapes or normal shapes, and then you choose which factory to use depending on the option whilst improving code maintainability and readability by using the same IShapeFactory* pointer.

share|improve this answer
1  
Please stop creating interfaces that pass around RAW pointers. Interfaces should define the ownership semantics of any objects that are dynamically created. –  Loki Astari Jul 13 at 16:25
    
@LokiAstari Surely it is an implementation detail of the factory as to whom the ownership of the object passes to once it has been created? –  Shaktal Jul 13 at 16:27
    
@LokiAstari Ahh, on reflection I think I understand what you mean; by returning a std::unique_ptr we "guarantee" (up to reasonable doubt) that this is the only copy of the pointer floating around and that when we delete our abstract factory, our pointer will still be valid. Is this what you mean? –  Shaktal Jul 13 at 16:33
    
If you have different factories implementing the ownership semantics in different ways then your program is going to break (because an application will work with one factory CNormalShapeFactory but then because of assumptions made about that factory the same code will break when used with CMagicShapeFactory). So no all factories must implement the same semantics. Also pointers do not convey any ownership semantics. So your code is now no longer any better than C code which means it can be used incorrectly. The point of C++ is that we can define our interfaces so they can not be misused –  Loki Astari Jul 13 at 16:34
    
There are multiple ways of doing this (the one I use above std::unique_ptr basically passes ownership back to the caller). Alternatively you can use std::shared_ptr to indicate shared ownership or you can return by reference indicating that the ownership is retained by the factory. All techniques have their pluses and minus. –  Loki Astari Jul 13 at 16:37

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.