Tuesday, September 10, 2013

Desing Patterns

Design patterns are solutions to general problems that software developers faced during software development. Design patterns are primarily based on the following principles of object orientated design
  1. Program to an interface not an implementation
  2. Favor object composition over inheritance.
Design patterns are of following categories:-
  1. Creational Patterns:- These design patterns provides way to create objects while hiding the creation logic and instantiating objects directly using new operator
    • Factory pattern   
      public
      interface Shape { void draw(); }
      public class Rectangle implements Shape {
         @Override
         public void draw() {
            System.out.println("Inside Rectangle::draw() method.");
         }
      }
      public class Square implements Shape {
         @Override
         public void draw() {
            System.out.println("Inside Square::draw() method.");
         }
      }
      public class Circle implements Shape {
         @Override
         public void draw() {
            System.out.println("Inside Circle::draw() method.");
         }
      }

      public
      class ShapeFactory { //use getShape method to get object of type shape
      public
      Shape getShape(String shapeType){ if(shapeType == null){ return null; } if(shapeType.equalsIgnoreCase("CIRCLE")){ return new Circle(); } else if(shapeType.equalsIgnoreCase("RECTANGLE")){ return new Rectangle(); } else if(shapeType.equalsIgnoreCase("SQUARE")){ return new Square(); } return null; } }
      
      
      public class FactoryPatternDemo {
         public static void main(String[] args) {
            ShapeFactory shapeFactory = new ShapeFactory();
            //get an object of Circle and call its draw method.
            Shape shape1 = shapeFactory.getShape("CIRCLE");
            //call draw method of Circle
            shape1.draw();
            //get an object of Rectangle and call its draw method.
            Shape shape2 = shapeFactory.getShape("RECTANGLE");
            //call draw method of Rectangle
            shape2.draw();
            //get an object of Square and call its draw method.
            Shape shape3 = shapeFactory.getShape("SQUARE");
            //call draw method of circle
            shape3.draw();
         }
      }
    •  Abstract Factory patterns It works as a super-factory which creates other factories
      public interface Shape { void draw(); }
      public class Rectangle implements Shape {
         @Override
         public void draw() {
            System.out.println("Inside Rectangle::draw() method.");
         }
      }
      public class Square implements Shape {
         @Override
         public void draw() {
            System.out.println("Inside Square::draw() method.");
         }
      }
      public class Circle implements Shape {
         @Override
         public void draw() {
            System.out.println("Inside Circle::draw() method.");
         }
      }
      
      public class ShapeFactory {
         //use getShape method to get object of type shape 
         public Shape getShape(String shapeType){
            if(shapeType == null){
               return null;
            }  
            if(shapeType.equalsIgnoreCase("CIRCLE")){
               return new Circle();
            } else if(shapeType.equalsIgnoreCase("RECTANGLE")){
               return new Rectangle();
            } else if(shapeType.equalsIgnoreCase("SQUARE")){
               return new Square();
            }
            return null;
         }
      }
      public class FactoryPatternDemo {
         public static void main(String[] args) {
            ShapeFactory shapeFactory = new ShapeFactory();
            //get an object of Circle and call its draw method.
            Shape shape1 = shapeFactory.getShape("CIRCLE");
            //call draw method of Circle
            shape1.draw();
            //get an object of Rectangle and call its draw method.
            Shape shape2 = shapeFactory.getShape("RECTANGLE");
            //call draw method of Rectangle
            shape2.draw();
            //get an object of Square and call its draw method.
            Shape shape3 = shapeFactory.getShape("SQUARE");
            //call draw method of circle
            shape3.draw();
         }
      }
      public interface Color {
         void fill();
      }
      public class Red implements Color {
         @Override
         public void fill() {
            System.out.println("Inside Red::fill() method.");
         }
      }
      public class Green implements Color {
         @Override
         public void fill() {
            System.out.println("Inside Green::fill() method.");
         }
      }
      public class Blue implements Color {
         @Override
         public void fill() {
            System.out.println("Inside Blue::fill() method.");
         }
      }
      public abstract class AbstractFactory {
         abstract Color getColor(String color);
         abstract Shape getShape(String shape);
      }
      public class ShapeFactory extends AbstractFactory { 
         @Override
         public Shape getShape(String shapeType){
            if(shapeType == null){
               return null;
            }  
            if(shapeType.equalsIgnoreCase("CIRCLE")){
               return new Circle();
            } else if(shapeType.equalsIgnoreCase("RECTANGLE")){
               return new Rectangle();
            } else if(shapeType.equalsIgnoreCase("SQUARE")){
               return new Square();
            }
            return null;
         }
         @Override
         Color getColor(String color) {
            return null;
         }
      }
      public class ColorFactory extends AbstractFactory { 
         @Override
         public Shape getShape(String shapeType){
            return null;
         } 
         @Override
         Color getColor(String color) {
            if(color == null){
               return null;
            }  
            if(color.equalsIgnoreCase("RED")){
               return new Red();
            } else if(color.equalsIgnoreCase("GREEN")){
               return new Green();
            } else if(color.equalsIgnoreCase("BLUE")){
               return new Blue();
            }
            return null;
         }
      }
      public class FactoryProducer {
         public static AbstractFactory getFactory(String choice){
            if(choice.equalsIgnoreCase("SHAPE")){
               return new ShapeFactory();
            } else if(choice.equalsIgnoreCase("COLOR")){
               return new ColorFactory();
            }
            return null;
         }
      }
      public class AbstractFactoryPatternDemo {
         public static void main(String[] args) {
            //get shape factory
            AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE");
            //get an object of Shape Circle
            Shape shape1 = shapeFactory.getShape("CIRCLE");
            //call draw method of Shape Circle
            shape1.draw();
            //get an object of Shape Rectangle
            Shape shape2 = shapeFactory.getShape("RECTANGLE");
            //call draw method of Shape Rectangle
            shape2.draw();
            //get an object of Shape Square 
            Shape shape3 = shapeFactory.getShape("SQUARE");
            //call draw method of Shape Square
            shape3.draw();
            //get color factory
            AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR");
            //get an object of Color Red
            Color color1 = colorFactory.getColor("RED");
            //call fill method of Red
            color1.fill();
            //get an object of Color Green
            Color color2 = colorFactory.getColor("Green");
            //call fill method of Green
            color2.fill();
            //get an object of Color Blue
            Color color3 = colorFactory.getColor("BLUE");
            //call fill method of Color Blue
            color3.fill();
         }
      } 
    •  Singleton pattern:- This pattern involves a single class which is responsible to creates own object while making sure that only single object get created.
      • Eager Initialization:- This is a design pattern where an instance of a class is created much before it is actually required.
        public class EagerSingleton {
            private static volatile EagerSingleton instance = new EagerSingleton();
            private EagerSingleton() {
            }
        public static EagerSingleton getInstance() {
            return instance;
            }
        }
      • LazyInitialization:- it restricts the creation of instance until requested first time.
        public final class LazySingleton {
            private static volatile LazySingleton instance = null;
            private LazySingleton() {
            }

            public static LazySingleton getInstance() {
                if (instance == null) {
                    synchronized (LazySingleton.class) {
                    instance = new LazySingleton();
                }
            }
            return instance;
            }
        }
      •  Double Checked Locking:- (see instance == null used twice)
        public final class LazySingleton {
            private static volatile LazySingleton instance = null;
            private LazySingleton() {
            }
            public static LazySingleton getInstance() {
                if (instance == null) {
                    synchronized (LazySingleton.class) {
                    if (instance == null) {
                        instance = new LazySingleton();
                    }
                }
            }
            return instance;
            }
        }
      • Static block initialization:-It makes use of the fact that static blocks are executed during the loading of class and even before the constructor is called.
        public class StaticBlockSingleton {
            private static final StaticBlockSingleton INSTANCE;
            static {
                try {
                    INSTANCE = new StaticBlockSingleton();
                } catch (Exception e) {
                    throw new RuntimeException("Uffff, i was not expecting this!", e);
                }
            }
            public static StaticBlockSingleton getInstance() {
                return INSTANCE;
            }
            private StaticBlockSingleton() {
            }
        }
      • Bill Pugh Solution:-The LazyHolder class will not be initialized until required and you can still use other static members
        public class BillPughSingleton {
            private BillPughSingleton() {
            }
            private static class LazyHolder {
                private static final BillPughSingleton INSTANCE = new BillPughSingleton();
            }
            public static BillPughSingleton getInstance() {
                return LazyHolder.INSTANCE;
            }
        }
    •  Builder pattern:- It builds a complex object using simple object.
      public interface Item {
         public String name();
         public Packing packing();
         public float price();   
      }
      public interface Packing {
         public String pack();
      }
      public class Wrapper implements Packing {
         @Override
         public String pack() {
            return "Wrapper";
         }
      }
      public class Bottle implements Packing {
         @Override
         public String pack() {
            return "Bottle";
         }
      }
      public abstract class Burger implements Item {
         @Override
         public Packing packing() {
            return new Wrapper();
         }
         @Override
         public abstract float price();
      }
      public abstract class ColdDrink implements Item {
          @Override
          public Packing packing() {
                    return new Bottle();
          }
          @Override
          public abstract float price();
      }
      public class VegBurger extends Burger {
         @Override
         public float price() {
            return 25.0f;
         }
         @Override
         public String name() {
            return "Veg Burger";
         }
      }
      public class ChickenBurger extends Burger {
         @Override
         public float price() {
            return 50.5f;
         }
         @Override
         public String name() {
            return "Chicken Burger";
         }
      }
      public class Coke extends ColdDrink {
         @Override
         public float price() {
            return 30.0f;
         }
         @Override
         public String name() {
            return "Coke";
         }
      }
      public class Pepsi extends ColdDrink {
         @Override
         public float price() {
            return 35.0f;
         }
         @Override
         public String name() {
            return "Pepsi";
         }
      }
      import java.util.ArrayList;
      import java.util.List;

      public class Meal {
         private List<Item> items = new ArrayList<Item>();   
         public void addItem(Item item){
            items.add(item);
         }
         public float getCost(){
            float cost = 0.0f;
            for (Item item : items) {
               cost += item.price();
            }       
            return cost;
         }
         public void showItems(){
            for (Item item : items) {
               System.out.print("Item : "+item.name());
               System.out.print(", Packing : "+item.packing().pack());
               System.out.println(", Price : "+item.price());
            }       
         }   
      }
      public class MealBuilder {
         public Meal prepareVegMeal (){
            Meal meal = new Meal();
            meal.addItem(new VegBurger());
            meal.addItem(new Coke());
            return meal;
         }  
         public Meal prepareNonVegMeal (){
            Meal meal = new Meal();
            meal.addItem(new ChickenBurger());
            meal.addItem(new Pepsi());
            return meal;
         }
      }
      public class BuilderPatternDemo {
         public static void main(String[] args) {
            MealBuilder mealBuilder = new MealBuilder();
            Meal vegMeal = mealBuilder.prepareVegMeal();
            System.out.println("Veg Meal");
            vegMeal.showItems();
            System.out.println("Total Cost: " +vegMeal.getCost());
            Meal nonVegMeal = mealBuilder.prepareNonVegMeal();
            System.out.println("\n\nNon-Veg Meal");
            nonVegMeal.showItems();
            System.out.println("Total Cost: " +nonVegMeal.getCost());
         }
      }
    • Prototype pattern:- It refers to creating duplicate object while keeping performance in mind.
  2. Structural Patterns:- These design patterns concern class and object composition. Concept of inheritance is used to compose interfaces and define ways to compose objects to obtain new functionalities.
  3. Behavioral Patterns

No comments:

Post a Comment

SpringBoot Application Event Listeners

When a spring boot application starts few events occurs in below order ApplicationStartingEvent ApplicationEnvironmentPreparedEvent Applicat...