Prototype design pattern for beginners.
Problem statement –
Let us first see what problem we are facing without
prototype. There are so many places, where you must have used themes to change look and feel of screen. i.e –
1.
Changing theme of your mobile screen or your
desktop screen.
2.
Changing theme of your FB page or Gmail page.
3.
Changing theme of e-greeting card.
Many
more ….
Recollect your memory on theme, on a single theme we can have many
colors. In many cases we have limited themes but with many colors option available, for example –
1.
Romantic theme (in 7 colors).
2.
Patriotic theme (in 7 colors).
3.
Warrior theme (in 7 colors).
Please understand, creating a theme is costly operation.
It has to apply specific query and fetch data from DB and construct object with
proper layout information.
For example, I have selected patriotic theme for my Gmail page, by
default it comes with white background color. I am not liking it in white background,
I don’t want to change theme, but I want to change it's color to red.
If we don’t use prototyping, we will create a new object of patriotic theme every time with different background color, with all costly operation again. But if you notice, we have old theme with color white in hand, all other properties like – layout, look and feels are same,
still we have created patriotic theme object with red color from scratch which is not a good programming practice.
What we could have done here?
Create patriotic theme object only once, store it in some cache memory. Make a copy of existing default patriotic theme object
(which we have already created once), without having any costly DB search on basis of patriotic
theme (as all info are available in object’s memory now) and change color to
red in new object.
No problem if you are not liking this particular example, think of any complex object creation according to your IT experience. If we have to create very similar object again and again with little or no properties changes, then it is a good idea to clone existing object (and apply changes on to the copy of object) instead of creating new object every time.
When do we use prototype design pattern –
Whenever we are applying very expensive operations (or
calculations) while creating the object.
In some big applications before crating object we may have to query
many things in DB, or stable connections to various hardware machines, for making system up and running.
Think if we have requirement to create different
objects of same type. We should take reference to already created
object, copy its all properties to new object, and apply new property changes on
the basis of business logic to, newly created object.
What is the difference between prototype and copay constructor in C++ -
If we think only from cloning prospective, of one type, then yes you may get confuse between copy constructor and prototype, but here we are talking about a polymorphic cloning on the basis of type of object. In Cpp, can I have a virtual constructor? No. It will
through a compilation error, we should know the type of object during
compilation otherwise it will throw an error. But what if I want to achieve
virtual constructor in cpp?
One of they way we can achieve virtual constructor through prototype design pattern.
apart form cloning we may have to add some more functionality like changing the behavior of cloned object through some manager class. which will be very easy if we apply prototype design pattern.
your code will become more manageable and understandable with prototype, otherwise you have to implement cloning and changing, and it's behavior, for each and every individually class level, and you will introduce more lines of code, which will end up with more numbers of bug, and you have to manage it, per class basis, not a good way to do, isn't it?
One of they way we can achieve virtual constructor through prototype design pattern.
apart form cloning we may have to add some more functionality like changing the behavior of cloned object through some manager class. which will be very easy if we apply prototype design pattern.
your code will become more manageable and understandable with prototype, otherwise you have to implement cloning and changing, and it's behavior, for each and every individually class level, and you will introduce more lines of code, which will end up with more numbers of bug, and you have to manage it, per class basis, not a good way to do, isn't it?
UML Structure -
C++ Example -
/************************************************************************************** /* this code is to represent prototype design pattern. /* /* (c) 2016 Kunjesh Singh Baghel, All Rights Reserved. /* https://sites.google.com/site/kunjeshsinghbaghel/ ***************************************************************************************/ //************************************************************************************* // Header files #include<iostream> #include<string> #include<map> using namespace std; //************************************************************************************* //Global variables and functions const string ROMANTIC = "RomanticTheme"; const string PATRIOTIC = "PatrioticTheme"; const string WARRIOR = "WarriorTheme"; //************************************************************************************* // Class class ITheme { public: virtual ITheme* clone() = 0; virtual void draw() = 0; virtual string getThemeName() = 0; virtual string getColorName() = 0; virtual void setColor(string color) = 0; }; //************************************************************************************* // Class class RomanticTheme : public ITheme { public: RomanticTheme(string color = "White"):m_color(color){} ITheme* clone() { return new RomanticTheme(*this); } void draw() { cout<< "Drowing RomanticTheme in " << m_color << " color " << endl; } string getThemeName() { return "RomanticTheme"; } string getColorName() { return m_color; } void setColor(string color) { m_color = color; } private: string m_color; }; //************************************************************************************* // Class class PatrioticTheme : public ITheme { public: PatrioticTheme(string color = "White"):m_color(color){} ITheme* clone() { return new PatrioticTheme(*this); } void draw() { cout<< "Drowing PatrioticTheme in " << m_color << " color " << endl; } string getThemeName() { return "PatrioticTheme"; } string getColorName() { return m_color; } void setColor(string color) { m_color = color; } private: string m_color; }; //************************************************************************************* // Class class WarriorTheme : public ITheme { public: WarriorTheme(string color = "White"):m_color(color){} ITheme* clone() { return new WarriorTheme(*this); } void draw() { cout<< "Drowing WarriorTheme in " << m_color << " color " << endl; } string getThemeName() { return "WarriorTheme"; } string getColorName() { return m_color; } void setColor(string color) { m_color = color; } private: string m_color; }; //************************************************************************************* // Class class ThemeManager { public: ThemeManager():m_themeAdded(false) {} void addTheme(); ITheme* getTheme(string theme); ITheme* getTheme(string theme , string color); private: map<string, ITheme*> m_dictionary; bool m_themeAdded; }; /////////////////////////////////////////////////////////////////////////////////////// void ThemeManager::addTheme() { // first we have all available themes in our dictionary m_dictionary.insert(pair<string, ITheme*>(ROMANTIC, (new RomanticTheme))); m_dictionary.insert(pair<string, ITheme*>(PATRIOTIC, (new PatrioticTheme))); m_dictionary.insert(pair<string, ITheme*>(WARRIOR, (new WarriorTheme))); } /////////////////////////////////////////////////////////////////////////////////////// ITheme* ThemeManager::getTheme(string theme) { if(!m_themeAdded) { addTheme(); } map<string, ITheme*>::iterator it = m_dictionary.find(theme); return it->second->clone(); } /////////////////////////////////////////////////////////////////////////////////////// ITheme* ThemeManager::getTheme(string theme, string color) { if(!m_themeAdded) { addTheme(); } map<string, ITheme*>::iterator it = m_dictionary.find(theme); it->second->setColor(color); return it->second->clone(); } //************************************************************************************* // Main functions int main(int argc, char** argv) { ThemeManager themeManagerObj; themeManagerObj.addTheme(); ITheme *iThemePtr = themeManagerObj.getTheme("PatrioticTheme"); iThemePtr->draw(); ITheme *iThemePtr02 = themeManagerObj.getTheme("PatrioticTheme", "Red"); iThemePtr02->draw(); return 0; } ///////////////////////////////////////////////////////////////////-------------OutPut /* $ ./a.exe Drowing PatrioticTheme in White color Drowing PatrioticTheme in Red color */
Thanks for reading it. To read more on design patterns and basic design principles please see my web page. You can also join me on FB or on G++. Please drop comments for any question related to this blog.
Comments
Post a Comment