dgurung
8/4/2015 - 1:07 AM

FactoryMethodDP.cpp

#include <iostream>
#include <memory>

// tags
enum genre_enum{ROCK, POP, REGGAE, INVALID};

/* Base CLass - Pure Abstract */
class Music{
public:
	virtual void song() = 0;
};

/* Derived class Rock from Music */
class Rock : public Music{
public:
	Rock(){};
	virtual ~Rock(){};

	virtual void
	song(){
		std::cout << "Nirvana: Smells like teen spirit\n";
	}
};

/* Derived class Rock from Music */
class Pop : public Music{
public:
	Pop(){};
	virtual ~Pop(){};

	virtual void
	song(){
		std::cout << "Michael Jackson: Billy Jeans \n";
	}
};

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

/* Design Pattern: Factory method implementation class*/


class MusicFactory{
public:
	/* Factory Method */
	virtual std::unique_ptr<Music> getMusic(genre_enum genre) = 0;
};


class Factory : public MusicFactory{
public:
	virtual std::unique_ptr<Music>
	getMusic(genre_enum genre){
			
		std::unique_ptr<Music> music(nullptr); 

		switch(genre){
			case ROCK:
				music = std::make_unique<Rock>();
				break;
			case POP:
				music = std::make_unique<Pop>();
				break;
			case REGGAE:
				music = std::make_unique<Reggae>();
			case INVALID:
				break;
		}

		return music;
	}
};


/*
There can be multiple Factory class each designed based on requirement. Example AsianMusicFactory, EuropeanMusicFactory classes
They all define the "getMusic(genre_enum genre)" method (aka factory method) in their class definition.
*/


int 
main(){
	std::unique_ptr<MusicFactory> musicFactory( std::make_unique<Factory>() );

	//std::unique_ptr<Music> music = musicFactory->getMusic(ROCK);
	auto music = musicFactory->getMusic(ROCK);
	if(music)
		music->song();
	else
		std::cout << "Wrong Selection.\n";

	music = musicFactory->getMusic(REGGAE);
	if(music)
		music->song();
	else
		std::cout << "Wrong Selection.\n";


	music = musicFactory->getMusic(INVALID);
	if(music)
		music->song();
	else
		std::cout << "Wrong Selection.\n";

	return 0;
}

/* OUTPUT:
	Nirvana: Smells like teen spirit
	Bob Marley: No woman, no cry 
	Wrong Selection.

We made three types of Music without knowing their specific class names. We defer the instantiation 
to Factory class to create the three objects (of Music class).

In essence, a factory method is a normal method which returns an instance of a class (in the example, 
it is an object of Music class).
*/

/* Reference
	[1] http://codereview.stackexchange.com/questions/56924/factory-design-pattern-with-music-classes

   Compile in linux terminal:
   	clang++ -std=c++14 -stdlib=libc++ FactoryMethodDP.cpp
*/