
- Image via Wikipedia
Today we will take a look at the abstract factory design pattern. This design pattern continues the series of creational patterns.
In previous article we have talked about factory pattern. We have learned that factory pattern deals with creation of other objects. Now we will extend that knowledge with the abstract factory pattern which provides a way to group together or rather encapsulate a group of individual factories that create objects with common theme.
Normally we would code a client software to create a concrete implementation of the abstract factory and then use generic interfaces to create concrete objects that are tuned to specific theme but, the client does not know about which concrete object will it get from each of the internal factories since it uses generic interfaces of the factory product in question. Details of the implementation of concrete objects are hidden by the internal factories.
Now lets look at an example.
In Java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | public class MusicalFactory { private MusicMedia media; private MusicalFactory() { } public MusicalFactory(MusicMedia _media) { media = _media; } public Music createMusic() { return media.createMusic(); } public interface Music { public String getName(); } public interface MusicMedia { public Music createMusic(); } public class Queen implements Music { public String getName() { return "Queen"; } } public class TheBeatles implements Music { public String getName() { return "The Beatles"; } } public class CompactDisc implements MusicMedia { public Music createMusic() { return new Queen(); } } public class LongPlay implements MusicMedia { public Music createMusic() { return new TheBeatles(); } } public static MusicMedia createMediaBasedOnEra(int _year) { if (_year < 1982) return new MusicalFactory().new LongPlay(); else return new MusicalFactory().new CompactDisc(); } public static void main(String[] argv) { if (argv.length == 1) { int year = Integer.parseInt(argv[0]); MusicalFactory factory = new MusicalFactory(createMediaBasedOnEra(year)); System.out.println("You love: " + factory.createMusic().getName()); } else { System.out.println("Usage: java MusicalFactory "); } } } |
In PHP:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | interface Music { function getName(); } interface MusicMedia { function createMusic(); } class Queen implements Music { function getName() { return "Queen"; } } class TheBeatles implements Music { function getName() { return "The Beatles"; } } class CompactDisc implements MusicMedia { function createMusic() { return new Queen(); } } class LongPlay implements MusicMedia { function createMusic() { return new TheBeatles(); } } class MusicalFactory { var $media; function MusicalFactory($media) { $this->$media = $media; } function createMusic() { return $media->createMusic(); } } function createMediaBasedOnEra($year) { if ($year < 1982) return new CompactDisc(); else return new LongPlay(); } $musicalFactory = new MusicalFactory(createMediaBasedOnEra(1980)); echo "You like: " . $musicalFactory->createMusic()->getName(); |
In Python:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | class Music: def getName(self): raise NotImplementedError class MusicMedia: def createMusic(self): raise NotImplementedError class Queen(Music): def getName(self): return "Queen" class TheBeetles(Music): def getName(self): return "The Beetles" class CompactDisc(MusicMedia): def createMusic(self): return Queen() class LongPlay(MusicMedia): def createMusic(self): return TheBeetles() class MusicalFactory(): musicalFactory = 0 def __init__(self, musicalFactory): MusicalFactory.musicalFactory = musicalFactory def createMusic(self): return MusicalFactory.musicalFactory.createMusic() def createMediaBasedOnEra(year): if year < 1982: return LongPlay() else: return CompactDisc() if __name__ == '__main__': factory = MusicalFactory(createMediaBasedOnEra(1980)) print "You like: %s" % factory.createMusic().getName() |
In C++:
Header file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | #include class Music { public: virtual std::string getName() = 0; }; class MusicMedia { public: virtual Music* createMusic() = 0; }; class Queen : public Music { public: virtual std::string getName(); }; class TheBeetles : public Music { public: std::string getName(); }; class CompactDisc : public MusicMedia { public: Music* createMusic(); }; class LongPlay : public MusicMedia { public: Music* createMusic(); }; class MusicFactory { public: MusicFactory(MusicMedia* factory); Music* createMusic(); private: MusicMedia* m_factory; }; |
And source file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | #include "abstractfactory.hpp" std::string Queen::getName() { return std::string("Queen"); } std::string TheBeetles::getName() { return std::string("The Beatles"); } Music* CompactDisc::createMusic() { return new Queen(); } Music* LongPlay::createMusic() { return new TheBeetles(); } MusicFactory::MusicFactory(MusicMedia* factory) { m_factory = factory; } Music* MusicFactory::createMusic() { return (m_factory->createMusic()); } MusicMedia* createMediaBasedOnEra(int _year) { if (_year < 1982) return new LongPlay(); else return new CompactDisc(); } int main(int argc, char *argv[]) { MusicFactory factory = MusicFactory(createMediaBasedOnEra(1980)); std::cout << "You like: " << factory.createMusic()->getName().c_str(); } |
The main idea of the example is that createMediaBasedOnEra() method creates a MusicMedia. MusicMedia is an abstract factory that can produce Music based on that era. Now the example is intended to show how we can hide implementation details.
As already shown factory is the location where objects are constructed. Pattern’s intent is to isolate the creation of objects from their usage. New derived types can be introduced in the code without significant code change to the base class. Downside of the implementation of this patten is additional complexity to the code. It can also mean additional initial effort for developers. You should weigh cost – benefit before implementation.
![Reblog this post [with Zemanta]](http://img.zemanta.com/reblog_e.png?x-id=c730b9a3-ea54-4299-919c-9ca75e3d58fb)
