Wednesday, September 4, 2013

In London you will never be hungry.

I recently arrived to London, I have to say that I am very impressed.
Everything is really beatiful and the weather is great. One of the things that kept my attention is the huge amount of places you can pick for eating. I love food, and while eating at an Indian place at whitechappel yesterday, I've got inspired for my next blog post.

Did your programming teacher ever gave you that exercise, where you had to create a program to pick some food from a restaurant menu and try to apply some design pattern to it?
While looking through the menu at that Indian place I was remembering that homework, and I think it was some kind of factory pattern what we were expected to use back then to solve it.

This article is about the "abstract factory" pattern. Because of its purpose, some people may also refer to it as the "Toolkit pattern".
Let's have a look at it...

The "abstract factory" pattern is an enhancement of the "factory method" pattern(maybe better to say-It uses it...). Let's just refresh quickly our minds about the "factory method" pattern.

The "factory method" pattern is a creational pattern that intents to release the client from the task of creating objects.
The main reasons are:
 -objects may have a complex/dependant initialization mechanism which does not interest the client.
 -the client doesn't know which is the object type that he needs until runtime.

To implement a factory method what we need is create a method that will take an argument(passed at runtime) and add to it conditional logic that will create one object type or other based on the passed parameter.

The only way in which abstract factory differs from factory method is that with abstract factory we just create factories and let the client use the factories for create objects.

Both "abstract factory" and "factory method" are widely used in software engineering. Now let's have look a simple example where an "abstract factory".

In this UML diagram, we see how the client interacts only with the abstract factory and even the objects that creates using those factories are abstract(Food). The client does not know or care at all how those objects are created. As a result, the client call is simplier and does not have complex conditional logic to decide the object that is required.


 public class Customer {  
   public void orderFood() {  
     System.out.println("Which type of food would you like?");  
     Scanner scanner = new Scanner(System.in);  
     System.out.println("1- Mexican");  
     System.out.println("2- Chinese");  
     System.out.println("3- Indian");  
     int option = scanner.nextInt();  
     FoodFactory factory = FactoryMaker.getFactory(option);  
     Food food = factory.prepareFood();  
     System.out.print("Here are your " + food.getClass().getName());  
   }  
 }  
In the above code we see what we just mentioned above. The client using the abstract factory only interacts with abstractions, so there is not much client code.
 public interface FoodFactory {  
   public Food prepareFood();  
 }  
If we want to extend our software and have some other types of factories, we need to implement the comon interface that the client uses to access the factories.
 public class MexicanFoodFactory implements FoodFactory {  
   @Override  
   public MexicanFood prepareFood() {  
     Scanner scanner = new Scanner(System.in);  
     System.out.println("Mexican food menu:");  
     System.out.println("1- Fajitas");  
     System.out.println("2- Tacos");  
     return getFood(scanner.nextInt());  
   }  
   private MexicanFood getFood(int choice) {  
     switch (choice) {  
       case 1:  
         return new Fajitas();  
       case 2:  
         return new Tacos();  
     }  
     return null;  
   }  
 }  
This code above is just one sample implementation of one of those factories. As you can see, it has a "factory method" pattern in itself that will help return the appropiate food object(Just notice that the return type is an abstract class)
 public class FactoryMaker {  
   public static FoodFactory getFactory(int choice) {  
     switch (choice) {  
       case 1:  
         return new MexicanFoodFactory();  
       case 2:  
         return new ChineseFoodFactory();  
       case 3:  
         return new IndianFoodFactory();  
     }  
     return null;  
   }  
 }  
But to allow the client create the factories we will need some kind of gadget that will allow the client create one factory or other at runtime. That is why we need this class called FactoryMaker(This is again another sample of "factory method" but it will return an abstract/interface type)
 public abstract class Food {  
 }  
 public abstract class MexicanFood extends Food {  
 }  
 public class Fajitas extends MexicanFood {  
 }  
This 3 classes above are just part of the domain model.If you want you can make abstract those that you don't need to instantiate using the "new" keyword. The factories task is to create each of the concrete objects but use abstract return types so the client does not know about the type of the object being returned.

 Even if this pattern looks really interesting there are 2 important disadvantages of using it:
 - the bigger the model gets(more products), the more difficult is to maintain.
 - it violates the open-closed principle


Bon Appetit!

1 comment:

Share with your friends