Monday, February 7, 2011

Going Technical .....Abstract Factory

Well , after taking a little break , here I am now again on the topic , GOF Design Patterns :). When I posted my first post related to design patterns I did not get any comments from my colleagues which made me to believe that no one interested in reading the blog :) haha..... By the way today one of my colleagues asked me if I made any new blog entries..great , now I know at least one person is reading the crazy stuff that I am putting here..well as long as there is one person who reads the blog , I would keep writing then ..:)

Last blog I explained what the Visitor pattern is and the intent of the pattern. Today lets talk about Abstract Factory pattern. If I ask someone how many design patterns he or she knows , this is one of the patterns which would always comes in the list of patterns that he or she remembers. But my honest question is , do you really understand the pattern and its usage or , you mention the pattern just because it is around you most frequently than others ? well which ever is your answer let me get into the ugly truth of this pattern :)

Lets begin with a simple examples , say you need to eat vegetables for your meal. You have two options either eat vegetable grown in INDIA or else eat vegetables grown in MALAYSIA. But you do not want to eat vegetables which are grown both INDIA and MALAYSIA at the same time. And also you have the freedom to change the country at any given time, for examples lets say you got sick of eating vegetables grown in INDIA then you can select vegetables grown in MALAYSIA from the next day.

Now lets say you need to store your vegetables in a safe place so that you can continue using those for daily food. In this case you would need some boxes in which you put different vegetables and then keep them in a store room which has a display board which you can use to show the current country. Now how are you going to keep track of which box contains which vegetables? well we could write the names of the vegetable outside the box so that we know what ever is inside is of the type that is written there. For examples if you use Carrot , Long Beans and Potatoes you would need three boxes and you would write down the names outside the box like "Carrot" , "Long Beans" , "Potatoes". Also the room in which you have kept these boxes is your "Store Room". Whenever you need to cook your food , what you do is simply go to the store room and then get some of Carrot from the box where there is Carrot , some of Long Beans from the box where there is Long Beans and some of Potatoes from the box where there is Potatoes.

When selecting the vegetable you do not worry about from which country they are because you are already aware of the country which is in the display board. On the other hand whenever you change the country you are NOT changing your Store room , neither the Boxes , all you change is the stuff inside the box and the name in the display board. So lets think that you need to use another country , say VIETNAM all you need to change is the name in the display board and stuff inside the boxes. You can continue to use your store room and boxes. Ok , how this thing is ever going to be related to Abstract Factory pattern ? aha .. the whole scenario represents a pretty good usage of the pattern. Lets look at the definition of this pattern "Abstract Factory is used to abstract away the creation of families of related objects without specifying the concrete classes"

The important words are "Families of related objects" and "Creation". well the word "Creation" is pretty straightforward but what about the other one "Families of related objects". This is equally important and you can not use Abstract Factory if the objects that are created do not belong to a single family and if they are in a way not related to each other. In above example the "Family" is VEGETABLE while all the vegetables are related to each other since they are just vegetables.

Now in the above example , the store room is similar to a Factory from which you get vegetables , so we can have a class which represents this store room , lets say the class is "AbstractVegetableFactory.java". And since we have a box which represents Carrots in general , lets have a class called "AbstractCarrot.java" , for the box which represents Long Beans in general lets have a class called "AbstractLongBean.java" and for the box which represents Potatoe in general lets have a class called "AbstractPotatoe.java". Now in the above example what we do is get carrot from the store room , so it is equivalent to getting an AbstractCarrot from AbstractVegetableFactory. So out implementation would be as follows,


package blog.gof.structural;

public abstract class AbstractVegetableFactory {

public abstract AbstractLongBean createAbstractLongBean();
public abstract AbstractPotatoe createAbstractPotate();
public abstract AbstractCarrot createAbstractCarrot();
}


package blog.gof.structural;

public abstract class AbstractLongBean {

}

package blog.gof.structural;

public abstract class AbstractPotatoe {

}

package blog.gof.structural;

public abstract class AbstractCarrot {

}

Well , the implementation above has abstracted the Vegetable family that we have been talking about so far. So when you need a Carrot all you do is first create an instance of the Factory and ask the factory to return a Carrot or any other type of vegetable supported by the factory itself. Now how we are going to make sure that whenever you need INDIAN vegetables that the returned vegetable is of INDIAN origin and whenever you need Malaysian vegetables that the returned vegetable is of MALAYSIAN origin. For that lets first assume INDIAN vegetables , lets say Carrot , we could have Indian Carrots which is represented by "IndianCarrot.java" who is extended from "AbstractCarrot.java"

package blog.gof.structural;

public class IndiaCarrot extends AbstractCarrot {

}

likewise ,

package blog.gof.structural;

public class IndianLongBean extends AbstractLongBean {

}

package blog.gof.structural;

public class IndianPotatoe extends AbstractPotatoe {

}

For vegetables of MALAYSIAN origin we could use a similar approach,

package blog.gof.structural;

public class MalaysianCarrot extends AbstractCarrot {

}

package blog.gof.structural;

public class MalaysianLongBean extends AbstractLongBean {

}

package blog.gof.structural;

public class MalaysianPotatoe extends AbstractPotatoe {

}

Ok, now we have represented different vegetables from different countries. But we still need factories which represents INDIAN vegetables factory and MALAYSIAN vegetable factory. Lets have IndianVegetableFactory.java which is extended from AbstractVegetableFactory.java to represent INDIAN vegetables

package blog.gof.structural;

public class IndianVegetableFactory extends AbstractVegetableFactory {

@Override
public AbstractCarrot createAbstractCarrot() {
return new IndiaCarrot();
}

@Override
public AbstractLongBean createAbstractLongBean() {
return new IndianLongBean();
}

@Override
public AbstractPotatoe createAbstractPotate() {
return new IndianPotatoe();
}

}

For MALAYSIAN vegetable factory we follow a similar approach ,

package blog.gof.structural;

public class MalaysianVegetableFactory extends AbstractVegetableFactory {

@Override
public AbstractCarrot createAbstractCarrot() {
return new MalaysianCarrot();
}

@Override
public AbstractLongBean createAbstractLongBean() {
return new MalaysianLongBean();
}

@Override
public AbstractPotatoe createAbstractPotate() {
return new MalaysianPotatoe();
}

}

Lets see the factories in action now ,

package blog.gof.structural;

public class PatternDemonstrationMain {

public static void main(String[] args) {

//Create a factory instance, the factory is now only returning
//objects which are produced in INDIA
AbstractVegetableFactory factory = new IndianVegetableFactory();
AbstractCarrot carrot = factory.createAbstractCarrot();
//Ok , the carrot created here is IDIAN carrot , because we are using
//INDIAN vegetable factory
//And same goes to potatoe and long beans as well
AbstractLongBean longbean = factory.createAbstractLongBean();
AbstractPotatoe potatoe = factory.createAbstractPotate();
//Now assume that one day you need to REUSE this piece of code
//You need to use vegetable factory , but this time the country is
//Malaysia.
//So how many lines of code you would change in this case to make this program
//work for Malaysia,
//Only one -->AbstractVegetableFactory factory = new IndianVegetableFactory();
//change the factory to be MalaysianVegetableFactoty and you are done
//you have abstracted the regional dependency and your code is verymuch reusable
//now
factory = new MalaysianVegetableFactory();
carrot = factory.createAbstractCarrot();
//Ok , the carrot created here is MALAYSIAN carrot , because we are using
//MALAYSIAN vegetable factory
//And same goes to potatoe and long beans as well
longbean = factory.createAbstractLongBean();
potatoe = factory.createAbstractPotate();

}

}

If you want to change the country from which you get your vegetables all you need to do is to replace the Factory with the correct factory implementation. Other than that you do not need to change anything else at all.

So basically the Abstract Factory pattern is useful when you have a Family of related objects to be created and if the objects that need to be created do not relate to each other then Abstract Factory is not a good choice.

If you think this post is useful you may comment on this , also if you need further assistance in understanding , you could also post your question as well...