HiveBrain v1.2.0
Get Started
← Back to all entries
principlecppModerate

Factory design pattern with music classes

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
factorywithdesignclassesmusicpattern

Problem

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 
    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()
     {
      coutgetMusic(ROCK);

     coutsong();
     else
      cout<<"Wrong selection dude/dudette !!";
    }

Solution

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

-
Do you need to create the factory dynamically.

A local object will probably do.

-
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 getMusic(genre_e genre) = 0;
};

class AsianMusicFactory: public MusicFactory
{
    public:
        virtual std::unique_ptr getMusic(genre_e genre);
};
class AfricanMusicFactory: public MusicFactory
{
    public:
        virtual std::unique_ptr getMusic(genre_e genre);
};
class EuropeanMusicFactory: public MusicFactory
{
    public:
        virtual std::unique_ptr getMusic(genre_e genre);
};
class SouthAmericannMusicFactory: public MusicFactory
{
    public:
        virtual std::unique_ptr getMusic(genre_e genre);
};
class NorthAmericannMusicFactory: public MusicFactory
{
    public:
        virtual std::unique_ptr getMusic(genre_e genre);
};
// Special factory used when running unit tests.
class UnitTestMusicFactory: public MusicFactory
{
    public:
        virtual std::unique_ptr 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  factory = createMusicFactory();
     return *factory;
}
// Never call this method directly.
// This function should only be called by getMusicFactory().
std::unique_ptr 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  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 = fac.getMusic(ROCK);

    coutsong();   // Should test for NULL
}

Code Snippets

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);
};
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
}

Context

StackExchange Code Review Q#56924, answer score: 13

Revisions (0)

No revisions yet.