Sunday, August 16, 2015

A love affair with Design Patterns - I

One day a friend asked me, "Dude, ever wonder why those KFC Chicken Buckets taste so awesome ? I ordered from them the other day, and it was awesome. Wonder how they make such stuff ! Devil's Dinner that night, Lol ! Wish I could steal their recipes and give it to one of my friends who is a professional chef and may be we could start a business. Lol, what say, mate ?"

My answer - "Boss, you will never know how they make such stuff, you say them Fiery Grilled, they will give you Fiery Grilled. And even if you steal their recipe you would not trump their business. Good luck."

So, what do you think is the answer to my friend's question. If you speak the language of software development, you might have answered it differently.

Let's dive in !

As most of us have guessed from the cartoon above, that there is something lurking behind we not knowing how KFC makes their Chicken products.If you have worked in or are learning Java or any OOP language you might be knowing about Inheritance, Composition, Polymorphism, Encapsulation, Abstract Classes and Interfaces but what you might not know is what's lurking behind all these paradigms in OOP.

There's a Design Pattern lurking behind !

If you are asked to code a simplified version of KFC system, you might typically  think about Chicken, Fries and Burgers but what might not occur to you in the first place is that :
  • Chicken, Fries and Burgers are all different but actually all are kinds of Products.
  • Chicken products are produced differently 
  • Fries are produced differently 
  • Burgers are produced differently 
  • But all of them are produced by some kind of a ProductCreator
And how these products are created, the customer ordering should not have any idea. So, may be a simplified version of  a typical code snippet looks like

public String getMyOrder(String choice){

switch(choice) {

   case "chicken" :

   Chicken c = new Chicken();
   return c.toString();
    
   case "fries" :

   Fries f = new Fries();
   return f.toString();

   case "burgers" :
   Burgers b= new Burgers();
   return b.toString();


   }

} 
And you are right. But do you see the problem here ? What if KFC adds Risottos and Pizzas tomorrow, you have to come back to this method and add all of them.You guessed it right, your code is open to modification but closed to extension whereas it should be the reverse. For 100 more products, 100 more "case" statements, ugly looking code and a maintenance nightmare follows. Chances are that the guy who maintains your code is a psychopath and knows where you live. He gets freaked out at this and comes and shoots you. In other words, this code will end you up in utter trouble in the future.

How to get rid of the mess ?
 
So now you would expect a Design Pattern come riding on a white horse to save your day so that you 
don't have to cancel your vacation.Well, of course !

And here it is : The Factory Design Pattern 

For every change, your code needs to be changed, or in other words, your code is tightly coupled to the 
creation of products and is not robust to CHANGE, the only constant in software development.
 
To save yourself you need to :

1. Loosely couple your product creation logic from the method getMyOrder()
2. Think something else other than new(), think of Abstractions.
3. Think of extending, not modifying.
4. Make your code open to extension, but closed for modification.
 
Let's start Re-Factoring !
 
As I said, Chicken, Fries and Burgers all are some kinds of Products 
 
Means :
 
1. Chicken IS-A Product
 
2. Fry IS-A Product
 
3. Burger IS-A Product 
 
And, "IS-A" means "Inheritance" 
 
Designing the Product
 
That means, we can realize each Chicken, each Fry, each Burger as extending some sort of a supertype
called Product which is an abstraction and Chicken, Fry and Burger are the concrete product 
subclasses/implementations.
 
1. We make a Product abstract supertype
 
 public abstract class Product {
 
 protected String name;
 protected int price;
 protected int numberOrdered;
 
 @Override
 public String toString() {
  return "Here is your "+this.numberOrdered+" "+this.name+" at "+ 
                        this.price*this.numberOrdered+ " bucks";
 }
 
 // the getter setters
} 
 
2. We make Chicken, Fry, Burger extend Product
 


public class Chicken extends Product {
 
 public Chicken(int numberOrdered){
  this.name = "Chicken";
  this.price=100;
  this.numberOrdered=numberOrdered;
}

} 
 

public class Fry extends Product {
 
public Fry(int numberOrdered){
  this.name = "Fry";
  this.price=50;
  this.numberOrdered=numberOrdered;
 }

} 
 
 
public class Burger extends Product {
 
 public Burger(int numberOrdered){
  this.name = "Burger";
  this.price=150;
  this.numberOrdered=numberOrdered;
 }

}
 
We are done with the Products, we need someone to create those yummy stuff now !

Yes, we need the Product Creators !
 
As I said, Chicken, Fry and Burgers are all created differently but they are created by some sort of a 
ProductCreator or a ProductFactory 

Means : 
 
1. ChickenFactory IS-A ProductFactory and produces Chicken
 
2. FryFactory IS-A ProductFactory and produces Fries
 
3. BurgerFactory IS-A ProductFactory and produces Burgers

Again, "Inheritance", where each of ChickenFactory, FryFactory and BurgerFactory are the
concrete implementations of the abstract supertype ProductFactory.
 
Note : The getMyOrder() method that we wrote above in our bad-code example is actually the
one residing in the ProductFactory.
 
Remember, we cannot cancel our vacation and for that we need to decouple the product creation 
logic from the getMyOrder() method.
 
What is the loose coupling in this context ? 

Loose coupling in the context here is equivalent to the client code(the getMyOrder() method) not having 
any idea how Chicken, Fry and Burger is created. All it knows that a Product is created.
 
This means the abstract ProductFactory has only knowledge of creating an abstract Product but lets its subclasses
decide which concrete product to create.
 
Designing the abstract ProductFactory


public abstract class ProductFactory {
 
 public String getMyOrder(int numberOrdered) {
  
  Product p = createYummyProduct(numberOrdered);
  return p.toString();
  
 }
 
 protected abstract Product createYummyProduct(int numberOrdered);

}
 
 
Things about the ProductFactory

1. It has our good old but badly coded getMyOrder() method in a different way. We no more have
    those messy switch-case statements here.
 
2. Since the getMyOrder() method is common for all the concrete product factories, we extract out the common 
    behavior and put them in their abstract supertype and make the concrete product factories inherit the default
    behavior
 
3. The getMyOrder() method now calls the createYummyProduct() method which is abstract here and all the
    getMyOrder() method  knows that it gets a Product and it does not know which concrete Product and 
    how it is being created. In other words, the getMyOrder() method have no idea about the concrete product
    creation logic. Voila ! We have achieved loose coupling.
 
4. Note what we earlier had in the getMyOrder() method and now what we have.
 
      Earlier

   Chicken c = new Chicken();
 
      Now 
    
   Product p = createYummyProduct(numberOrdered);
 
   We no more have new() here. 
 
5. Also we are using abstract Product and not a concrete Chicken or a Fry or a Burger.  We are not 
   depending on a concrete implementation rather we are depending on an abstraction. In other words, 
   we are "Coding to an Abstraction".
 
Letting the Subclasses Decide 

The createYummyProduct() method looks mysterious and indeed it is. In the Factory Design Pattern
this is our factory method. The mystery here is it is "abstract". That means the concrete Product
Factories must give it a concrete implementation. In other words, the abstract ProductFactory by
defining the factory method abstract, lets its subclasses decide to provide the concrete creational
logic for each concrete product.
 
The createYummyProduct() method has only one job in life and that is to create a Product yet it has
some method signature. What do you call that thing in OOP, which creates an object, looks like a method
but is not a method ? A constructor !

The createYummyProduct() has only one job in life of creating a Product, is a method so it cannot be a constructor 
but looks like a constructor. 

And hence, we call the factory method createYummyProduct() a Virtual Constructor.
 
Designing the concrete ProductFactories
 
 public class ChickenFactory extends ProductFactory {

 @Override
 protected Product createYummyProduct(int numberOrdered) {

           return new Chicken(numberOrdered);
 }

}
public class FryFactory extends ProductFactory {

 @Override
 protected Product createYummyProduct(int numberOrdered) {

           return new Fry(numberOrdered);
 }

} 
 
 
public class BurgerFactory extends ProductFactory {

 @Override
 protected Product createYummyProduct(int numberOrdered) {

           return new Burger(numberOrdered);
 }

}
 
 
 
 
 



"We have done enough, let's enjoy our vacation and have a Sumptuous dinner !"

 

 

 

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
public class KFCApp {

 public static void main(String[] args) {
  
  try {
  Map<String, ProductFactory> choiceProductFactoryMap = new HashMap<String, ProductFactory>();
  choiceProductFactoryMap.put("C", new ChickenFactory());
  choiceProductFactoryMap.put("F", new FryFactory());
  choiceProductFactoryMap.put("B", new BurgerFactory());
  
  System.out.print("What you want ? (C/F/B) : ");
  BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
  
  String choice = br.readLine();
    
  while (!choiceProductFactoryMap.containsKey(choice.toUpperCase())) {
   
   System.out.println("You entered a wrong choice !\n");
   System.out.print("What you want ? (C/F/B) : ");
   br = new BufferedReader(new InputStreamReader(System.in));
   choice = br.readLine();
   
  }
  
    System.out.print ("How many ? : ");
    int numberOrdered = Integer.parseInt(br.readLine());
    ProductFactory pf = choiceProductFactoryMap.get(choice.toUpperCase());
    System.out.println(pf.getMyOrder(numberOrdered));
  }
  
  catch(IOException ioe){
   // LOG the exception
  }
  

 } 
 
     
Results 

What you want ? (C/F/B) : C
How many ? : 4
Here is your 4 Chicken at 400 bucks
 
What you want ? (C/F/B) : B
How many ? : 5
Here is your 5 Burger at 750 bucks
  
What you want ? (C/F/B) : F
How many ? : 10
Here is your 10 Fry at 500 bucks
 
What about CHANGE ?

So, how this code is robust when there is a change ? It is robust because when tomorrow KFC adds Risottos to its
menu, you just need to make a Risotto class make it extend Product and also make a RisottoFactory
extend ProductFactory and we are done. Just put that particular value in the map in the main class and we are done.

The idea of being robust to change is not that our code would not need any modification but it will need minimal
modifications to accommodate the change and it should be up and running.

What's the thing about Abstractions here ?

In the Factory Design Pattern, we can see that the classes responsible for creating a Product which are the 
ProductFactories here (the High Level Classes) depend upon the abstract ProductFactory to delegate
object creation decisions at runtime to them. Similarly, the concrete Product classes(the Low Level Classes)
depend upon the abstract Product and gets created at runtime by the concrete ProductFactories.

The Dependency Inversion Principle

The thing about abstractions above gives rise to a very important OO Design Principle, the Dependency Inversion
Principle which says :
 
1. High level classes should not depend on low level classes. Both should depend upon abstractions.
2. Abstractions should not depend upon details. Details should depend upon abstractions.
 
The typical way you would look at your OO Design is not the actual thing, it is actually inverted in this design. 
 
The Holy Class Diagram




 
 











 
 
 
 
 
 
 
 
 
 
 
 
That's how the Class Diagram looks like. The Abstract Product Factory has only the knowledge of the Abstract
Product and only the Concrete Product factory has the knowledge of the Concrete Product.
 
The Factory Method gives rise to a parallel-class hierarchy that inverts the dependency between the interacting classes
making us code to an abstraction, decouple and encapsulate object-creation logic and letting us enjoy our vacation.
 


That's it on the Factory Design Pattern. This is one of my most favorite design patterns that I have used
  
And yes, we owe to this Design Pattern for letting us enjoy our vacation as the other guy maintains our code.
 
  

If you have reached this far down, I hope you liked this. If I missed out on something, or I need to add something more,
kindly do let me know by posting a comment.
 
The love affair continues with Design Patterns and I believe, it would be quite a lengthy one. 
 
Cheers ! 





No comments :

Post a Comment