Saturday 5 September 2015

Design Patterns in Java

SingleTon design pattern

packageswain.singleton.javainterviewhub.blogspot.in.designpattern.singleton;

public class SingleObject {

       public static SingleObject singleton = new SingleObject();

       private SingleObject() {

       }

       public static SingleObject getInstance() {
              return singleton;
       }
      
       public void showMessage(){
              System.out.println("hello world");
       }

}


packageswain.singleton.javainterviewhub.blogspot.in.designpattern.singleton;

public class SingletonPatternDemo {

       public static void main(String[] args) {
              SingleObject singleObject=SingleObject.getInstance();
              singleObject.showMessage();
       }

}

There are three cases singleton class fail
1) Serialization :We can create multiple instance by searialization case.
2) Multi threading :Singleton class not thread safe
3) Class loader: We can create multiple instance with different class loader

Strategy design pattern
For our example, we will try to implement a simple Shopping Cart where we have two payment strategies – using Credit Card or using PayPal.  First of all we will create the interface for our strategy, in our case to pay the amount passed as argument.



packageswain.pattern.strategy;

public interface PaymentStrategy {
       public void pay(int amount);
}


Now we will have to create concrete implementations of algorithms for payment using credit/debit card or through paypal.
packageswain.pattern.strategy;

public classCreditCardPaymentStrategy implements PaymentStrategy {

       private String name;
       private String cardNumber;
       private String cvv;
       private String dateOfExpireDate;

       public CreditCardPaymentStrategy(String name, String cardNumber,
                     String cvv, String dateOfExpireDate) {
              this.name = name;
              this.cardNumber = cardNumber;
              this.cvv = cvv;
              this.dateOfExpireDate = dateOfExpireDate;
       }

       @Override
       public void pay(int amount) {
              System.out.println(amount + " payment with credit/debit card.");
       }

}

packageswain.pattern.strategy;

public classPaypalPaymentStrategy implements PaymentStrategy {
       private String emailId;
       private String password;

       publicPaypalPaymentStrategy(String emailId, String password) {
              this.emailId = emailId;
              this.password = password;
       }

       @Override
       public void pay(int amount) {
              System.out.println(amount + " payment with paypal.");

       }

}


Now our algorithms are ready and we can implement Shopping Cart and payment method will require input as Payment strategy.

packageswain.pattern.strategy;

public class Items {
       private String upcCode;
       private int price;

       public Items(String upcCode, int price) {
              this.upcCode = upcCode;
              this.price = price;
       }

       public String getUpcCode() {
              return upcCode;
       }

       public int getPrice() {
              return price;
       }

}


packageswain.pattern.strategy;

import java.util.ArrayList;
import java.util.List;

public class ShoppingCart {
       List<Items> items;

       public ShoppingCart() {
              this.items = newArrayList<Items>();
       }

       public void addItems(Items items) {
              this.items.add(items);
       }

       public void removeItems(Items items) {
              this.items.remove(items);
       }

       public int calculateTotal() {
              int sum = 0;
              for (Items items : this.items) {
                     sum += items.getPrice();

              }
              return sum;
       }

       public void pay(PaymentStrategy paymentStrategy) {
              int amount = calculateTotal();
              paymentStrategy.pay(amount);

       }

}


Notice that payment method of shopping cart requires payment algorithm as argument and doesn’t store it anywhere as instance variable.
Let’s test our setup with a simple program.


packageswain.pattern.strategy;

public class ShoppingCartTest {

       public static void main(String[] args) {
              ShoppingCart shoppingCart = new ShoppingCart();
             
              Items item1 = new Items("12345", 500);
              Items item2 = new Items("6789", 1000);
             
              shoppingCart.addItems(item1);
              shoppingCart.addItems(item2);
             
              //By credit card
              shoppingCart.pay(new CreditCardPaymentStrategy("sitansu s swain","123456","128","9/6/15"));
             
              //By pay pal
              shoppingCart.pay(newPaypalPaymentStrategy("swainsitansu@gmail.com","9718954323"));
       }

}


Output of above program is:
1500 payment with credit/debit card.
1500 payment with paypal.
Important Points
·           We could have used composition to create instance variable for strategies but we should avoid that as we want the specific strategy to be applied for a particular task, same is followed in Collections.sort() and Arrays.sort() method that take comparator as argument.

·           Strategy Pattern is very similar to State Pattern. One of the difference is that Context contains state as instance variable and there can be multiple tasks whose implementation can be dependent on the state whereas in strategy pattern strategy is passed as argument to the method and context object doesn’t have any variable to store it.


·           Strategy pattern is useful when we have multiple algorithms for specific task and we want our application to be flexible to chose any of the algorithm at runtime for specific task



Factory design Pattern

Factory pattern is one of most used design pattern in Java. This type of design pattern comes under creational pattern as this pattern provides one of the best ways to create an object.


In Factory pattern, we create object without exposing the creation logic to the client and refer to newly created object using a common interface.

packageswain.pattern.Factory;

public interface Shape {
      
       public void draw();

}


package swain.pattern.Factory;

public class Circle implements Shape{

       @Override
       public void draw() {
       System.out.println("Draw Circle");
             
       }

}


packageswain.pattern.Factory;

public class Rectangle implements Shape{

       @Override
       public void draw() {
              System.out.println("Draw Rectangle");
             
       }

}


packageswain.pattern.Factory;

public class Square implements Shape{

       @Override
       public void draw() {
              System.out.println("Draw Square");
             
       }

}


packageswain.pattern.Factory;

public class ShapeFactory {
       public ShapegetShape(String shapeType) {
             if (shapeType == null) {
                     returnnull
              }

              if(shapeType.equalsIgnoreCase("Circle")) {
                     returnnew Circle();
              }
              if(shapeType.equalsIgnoreCase("Rectangle")) {
                     returnnew Rectangle();
              }
              if(shapeType.equalsIgnoreCase("Square")) {
                     returnnew Square();
              }
              returnnull;
       }

}


packageswain.pattern.Factory;

public class FactoryPatternDemo {

       public static void main(String[] args) {
              ShapeFactory shapeFactory = new ShapeFactory();
              Shape shape1 = shapeFactory.getShape("Circle");
              shape1.draw();
              Shape shape2 = shapeFactory.getShape("Rectangle");
              shape2.draw();
              Shape shape3 = shapeFactory.getShape("Square");
              shape3.draw();

       }

}


Output:

Draw Circle
Draw Rectangle
Draw Square

 Prototype  Design Pattern

Prototype pattern refers to creating duplicate object while keeping performance in mind. This type of design pattern comes under creational pattern as this pattern provides one of the best ways to create an object.


This pattern involves implementing a prototype interface which tells to create a clone of the current object. This pattern is used when creation of object directly is costly. For example, an object is to be created after a costly database operation. We can cache the object, returns its clone on next request and update the database as and when needed thus reducing database calls.

packageswain.pattern.Prototype;

public abstract  class Shape implements Cloneable {
       private String id;

       protected String type;

       abstract void draw();
      
       public String getId() {
              return id;
       }

       public void setId(String id) {
              this.id = id;
       }

       public String getType() {
              return type;
       }
      
       public Object clone(){
              Object clone=null;
              try {
                     clone=super.clone();
              } catch(CloneNotSupportedException e) {
                     // TODO Auto-generated catch block
                     e.printStackTrace();
              }
              return clone;
       }
      
      
}

packageswain.pattern.Prototype;

public class Rectangle extends Shape {
       public Rectangle(){
              type="Rectangle";
       }

       @Override
       void draw() {
              System.out.println("Draw Rectangle");
       }

}


packageswain.pattern.Prototype;

public class Square extends Shape {
       public Square() {
              type = "Square";
       }

       @Override
       void draw() {
              System.out.println("Draw Square");

       }

}


packageswain.pattern.Prototype;

public class Circle extends Shape {
       public Circle() {
              type = "Circle";
       }

       @Override
       void draw() {
              System.out.println("Draw Circle");
       }

}

Create a class to get concrete classes from database and store them in a Hashtable.

packageswain.pattern.Prototype;

import java.util.Hashtable;

public class ShapeCache {

       private static Hashtable<String, Shape> shapeMap = new Hashtable<String, Shape>();

       public static Shape getShape(String shapeID) {
              Shape cachedShape = shapeMap.get(shapeID);
              return (Shape) cachedShape.clone();

       }

       public static void loadCache() {
              Circle circle = new Circle();
              circle.setId("1");
              shapeMap.put(circle.getId(), circle);

              Rectangle rectangle = new Rectangle();
              rectangle.setId("2");
              shapeMap.put(rectangle.getId(), rectangle);

              Square square = new Square();
              square.setId("3");
              shapeMap.put(square.getId(), square);

       }

}

PrototypePatternDemo uses ShapeCache class to get clones of shapes stored in aHashtable.
packageswain.pattern.Prototype;

public class PrototypePatternDemo {

       public static void main(String[] args) {
              ShapeCache.loadCache();

              Shape clonedShape1 = ShapeCache.getShape("1");
              System.out.println("Shape : " + clonedShape1.getType());

              Shape clonedShape2 = ShapeCache.getShape("2");
              System.out.println("Shape : " + clonedShape2.getType());

              Shape clonedShape3 = ShapeCache.getShape("3");
              System.out.println("Shape : " + clonedShape3.getType());

       }

}


Output:

Shape : Circle
Shape : Rectangle

Shape : Square




Producer Consumer Pattern

BlockingQueue amazingly simplifies implementation of Producer-Consumer design pattern by providing outofbox support of blocking on put() and take(). Developer doesn't need to write confusing and critical piece of wait-notify code to implement communication. BlockingQuue is an interface and Java 5 provides different implantation like ArrayBlockingQueue and LinkedBlockingQueue , both implement FIFO order or elements, while ArrayLinkedQueue is bounded in nature LinkedBlockingQueue is optionally bounded. here is a complete code example of Producer Consumer pattern with BlockingQueue. Compare it with classic wait notify code, its much simpler and easy to understand.


importjava.util.concurrent.BlockingQueue;
importjava.util.concurrent.LinkedBlockingQueue;
importjava.util.logging.Level;
importjava.util.logging.Logger;

public class ProducerConsumerPattern{

    public static void main(String args[]){
 
     //Creating shared object
     BlockingQueue sharedQueue = new LinkedBlockingQueue();

     //Creating Producer and Consumer Thread
     Thread prodThread = new Thread(new Producer(sharedQueue));
     Thread consThread = new Thread(new Consumer(sharedQueue));

     //Starting producer and Consumer thread
     prodThread.start();
     consThread.start();
    }

}

//Producer Class in java
class Producer implements Runnable {

    private final BlockingQueuesharedQueue;

    public Producer(BlockingQueuesharedQueue) {
        this.sharedQueue = sharedQueue;
    }

    @Override
    public void run() {
        for(int i=0; i<10; i++){
            try {
                System.out.println("Produced: " + i);
                sharedQueue.put(i);
            } catch(InterruptedException ex) {
                Logger.getLogger(Producer.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

}

//Consumer Class in Java
class Consumer implements Runnable{

    private final BlockingQueuesharedQueue;

    public Consumer (BlockingQueuesharedQueue) {
        this.sharedQueue = sharedQueue;
    }
 
    @Override
    public void run() {
        while(true){
            try {
                System.out.println("Consumed: "+ sharedQueue.take());
            } catch(InterruptedException ex) {
                Logger.getLogger(Consumer.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
 
 
}

Output:
Produced: 0
Produced: 1
Consumed: 0
Produced: 2
Consumed: 1
Produced: 3
Consumed: 2
Produced: 4
Consumed: 3
Produced: 5
Consumed: 4
Produced: 6
Consumed: 5
Produced: 7
Consumed: 6
Produced: 8
Consumed: 7
Produced: 9
Consumed: 8
Consumed: 9







    No comments:

    Post a Comment