This is going to be a simple C++ based tutorial on Abstract Factory Pattern. The sample used easy to understand and relate to. This pattern is closely related to Factory Method Pattern. I have a small post dedicated to it. I will encourage you to read it first before taking up this one.
For a definition of Abstract Factory Pattern wikipedia is a nice starting point. And it has one messy UML diagram.
As usual I will start with WHY and then follow it up with HOW.
WHY
In simple Factory Method Pattern, you ask a class to make an object you need. Or in real world terms, you ask someone to create and return to you something you want. You do not really want to know the details. Like in the blog post for Factory Method Pattern, I had given an example of a florist. You tell him what you kind of bouquet you want and he will send you the same. Abstract Factory Pattern takes this one level up. It deals with creation of a set of related objects, not one object.
Wait a min. What was that?
Suppose you are furnishing your home. You want to buy applicances. Now you can call up Samsung showroom and tell them to send you a fridge, washing machine and a dishwasher. Did you see the link? All are white goods and usually a company will manufacture the whole range of white goods. A factory producing a set of related items.
Ok. So you wanted a set of related objects. You created a factory which makes them. And you get the objects from it. This was a kind of a dissapointment. I was expecting more !!
Well to answer this question let us go back to the white goods example. Suppose after sometime you get bored of Samsung and decide that you want Whirlpool applicances. So you call them up and then they send you a fridge, washing machine and a dishwasher.
Do you build a new house to fit the appliances from a different manufacturer? Of course no. You just swap the machines and everything works as before. Nothing in your house changes. The way you use the applicances also does not change.
- You still open the fridge in the middle of night.
- You still leave washed clothes in the washing machine.
- You still start the dishwasher only when there are no more clean plates to be seen
- And to repeat you certainly did not have to build a new house just so that you can fit in your new applicances.
In short nothing changes. And that is the beauty of Abstract Factory Pattern. You can swap the source of the objects without changing the client code.
HOW
Time for some code now. I will use this same white goods example to illustrate the pattern. As usual all the interfaces and classes are dumped into one file. But then this is a demo. You will keep the interfaces and classes all in seperate files.
//C++ Code #include<iostream> #include<string> using namespace std; class IFridge { public: virtual string Run(void) = 0; }; class FridgeSamsung : public IFridge { public: string Run(void) { return "You are now running Samsung Fridge\n"; } }; class FridgeWhirlpool : public IFridge { public: string Run(void) { return "You are now running Whirlpool Fridge\n"; } }; class IWashingMachine { public: virtual string Run(void) = 0; }; class WashingMachineSamsung : public IWashingMachine { public: string Run(void) { return "You are now running Samsung Washing Machine\n"; } }; class WashingMachineWhirlpool : public IWashingMachine { public: string Run(void) { return "You are now running Whirlpool Washing Machine\n"; } }; class IFactory { public: virtual IFridge* GetFridge(void) = 0; virtual IWashingMachine* GetWashingMachine(void) = 0; }; class FactorySamsung : public IFactory { IFridge* GetFridge(void) { return new FridgeSamsung(); } IWashingMachine* GetWashingMachine(void) { return new WashingMachineSamsung(); } }; class FactoryWhirlpool : public IFactory { IFridge* GetFridge(void) { return new FridgeWhirlpool(); } IWashingMachine* GetWashingMachine(void) { return new WashingMachineWhirlpool(); } }; int main() { IFridge* fridge; //Client just knows about fridge and washingMachine. IWashingMachine* washingMachine; //and factory. He will write operations which IFactory* factory; //work on fridges and washingMachines. factory = new FactorySamsung; //This is the only place where the client //has to make a choice. //The rest of the code below will remain same, even //if the factory is changed. He can change the factory and the same range //of products but from a different factory will be returned. No need to //change any code. fridge = factory->GetFridge(); cout << fridge->Run(); washingMachine = factory->GetWashingMachine(); cout << washingMachine->Run(); cout << "\n"; delete factory; factory = new FactoryWhirlpool; //See same client code. fridge = factory->GetFridge(); cout << fridge->Run(); washingMachine = factory->GetWashingMachine(); cout << washingMachine->Run(); cout << "\n"; delete factory; return 1; }
Let us step through the code to get a better picture.
- Line 7 – We declare an interface of type IFridge. The client will deal with this. It will be blind to the actual objects implementing this interface which will be returned by the factory. As long as the object implements the IFridge interface client is happy. It is this which allows easy swapping of the factories without changing the client code.
- Line 13 – This is a class implementing the IFridge interface. It will be important to the Samsung Factory and not the client.
- Line 22 – This is a class implementing the IFridge interface for the Whirlpool factory.
- Line 31 – We declare an interface of type IWashingMachine. Similar story as IFridge interface.
- Line 37 – This is class implementing the IWashingMachine for Samsung factory.
- Line 46 – This is class implementing the IWashingMachine for the Whirlpool factory.
- Line 55 – The IFactory interface. The client will deal with this only. Notice the Get methods for Fridge and Washing machine. Client will use them to get the applicances.
- Line 62 – The Samsung Factory class defined.
- Line 66 – See how the Samsung factory is creating an instance of Samsung Fridge and returning it under its GetFridge method implementation.
- Line 71 – Samsung factory creates an instance of Samsung Washing machine and returns it under its GetWashingMachine method implementation.
- Line 75 – Whirlpool factory created.
- Line 79 – Whirlpool factory creates an instance of Whirlpool Fridge and returns it under its GetFridge method implementation.
- Line 84 – Whirlpool factory creates an instance of Whirlpool Washing machine and returns it under its GetWashingMachine method implementation.
- Line 90 – Action begins in client code. He declares a pointer to IFridge interface. This is just a demo. Pointers are evil.
- Line 91 – Pointer to IWashingMachine.
- Line 92 – Pointer to IFactory.
- Line 94 – This is the place where the client has to state which factory he wants. I went for Samsung factory first. The the appliances are fetched and then stored in the pointers and then run. Not that the client still does not care about the type of the appliances. All he wants is that they implement the interface.
- Line 110– The factory gets swapped. And then again the same client code is reapeated. And the result is as below.
You are now running Samsung Fridge
You are now running Samsung Washing Machine
You are now running Whirlpool Fridge
You are now running Whirlpool Washing Machine
Now your client code is resiliant. It can handle any range of products provided:
- The products implement the agreed set of interfaces.
- The actual factory implements the agreed factory interface.
Still not impressed?
An example from real world maybe? In telecom industry the billing is done by specialist servers known as billing servers. There are different vendors in this field. And each one communicates differently. One expects XML serialized content. Another just a file in its own proprietry format and so on. Suppose your software has to connect with any billing system and to pass on the data to it. And process the response.
So to go about it?
Lets use Abstract factory here.
- Create an interface IBillingSystem and put two methods in the interface, Connect() returning a IConnectionObject and Process() returning IResult object.
- Your client which will interfact will billing systems which work only in terms of these interfaces.
- Create class like MegaBillingSolutionServer implementing the IBillingSystem and its methods in its own specifc way.
- Suddenly your client code is much simpler. Only at on place it has to specify that it wants to use MegaBillingSolutionServer (Good place will be in the initialization section). Rest of it will be happily dealing with IBillingSystem, IConnectionObject and IResult interfaces.
- Now suppose you have to deal with new market leader in billing server. Stronger and cheaper, GigaBillingSolution billing server. Simple. You create a class GigaBillingSolutionServer and pass an instance of that in place where the client code specifies where which factory to use (Initialization section most likely). And rest remains unchanged. Simple. And Sweet.
Abstract Factory Pattern is a little difficult to get a hang of. But at the end of it, it is rather simple. Create related objects.
If you have any questions do write in comments section. I will try to answer.