Sunday 22 June 2014

Observer Design Pattern (with and without Java API)



It’s a behavioral pattern and can be understood as publish-subscribe model. An object notifies to other objects about his state changes.
“This pattern talks about one-to-many dependency b/w objects to provide a behavior where change of one object state would be notified to other objects and those objects would be updated accordingly as well.”
An object which is being watched known as ‘Subject’. An object which is watching the state is known as ‘Observer’ or ‘Listener’.

Example:
               1) Using my own implementation as below:
Observer.java
interface Observer {      
               void update(Object newsContent);
}

Subject.java
import java.util.ArrayList;
public abstract class Subject {
               protected ArrayList<Observer> observers = new ArrayList<Observer>();  
               public void registerObserver(Observer observer) {         
                              observers.add(observer);
               }
               public void removeObserver(Observer observer) {         
                              observers.remove(observer);
               }
 
               public abstract void notifyObservers();
               public void notifyObservers(Object obj){
                              for (Observer ob : observers) {                  
                                             System.out.println("Notifying Observers on change...");             
                                             ob.update(obj);           
                              }
               }
}

News.java
public class News extends Subject {      
               private String newsContent;     
               private String advertisement;     
               private int noOfPages;
               public News(String newsContent, String advertisement, int noOfPages) {
                              this.newsContent = newsContent;            
                              this.advertisement = advertisement;          
                              this.noOfPages = noOfPages;     
               }
               @Override
               public void notifyObservers() {   
                              for (Observer ob : observers) {                  
                                             System.out.println("Notifying Observers on change...");             
                                             ob.update(this.newsContent);           
                              }
               }
               public String getNewsContent() {
                              return newsContent;
               }
               public void setNewsContent(String newsContent) {
                              this.newsContent = newsContent;
                              notifyObservers();
               }
               public String getAdvertisement() {
                              return advertisement;
               }
               public void setAdvertisement(String advertisement) {
                              this.advertisement = advertisement;
                              notifyObservers(this.advertisement);
               }
               public int getNoOfPages() {
                              return noOfPages;
               }
               public void setNoOfPages(int noOfPages) {
                              this.noOfPages = noOfPages;
               }
}

ElectronicNewsPaper.java
public class ElectronicNewsPaper implements Observer {  
               @Override     
               public void update(Object newsContent) {   
                              System.out.println("ElectronicNewsPaper Today's News Content : " + (String)newsContent);    
                              //Business-logic to update the Electronic News-Paper
               }
}

PrintNewsPaper.java
public class PrintNewsPaper implements Observer {     
               @Override    
               public void update(Object newsContent) {   
                              System.out.println("PrintNewsPaper Today's News Content : " + (String)newsContent);   
                              //Business-logic to update the Print News-Paper
               }
}

ObserverClient.java
public class ObserverClient {
               public static void main(String args[]) {
                              PrintNewsPaper printMedia = new PrintNewsPaper();             
                              ElectronicNewsPaper electronicMedia = new ElectronicNewsPaper();
                              News todayNews = new News("today's News........................", "today's Advertisement...........s", 12);    
                              todayNews.registerObserver(printMedia);          
                              todayNews.registerObserver(electronicMedia);     
                              todayNews.setNewsContent("today's News got updated...................");
                               System.out.println("=================================================");
                              todayNews.removeObserver(electronicMedia);
                              todayNews.setNewsContent("today's News again got updated...................");
                              todayNews.setAdvertisement("today's Advertisement got updated...................");
               }
}

Output:-
Notifying Observers on change...
PrintNewsPaper Today's News Content : today's News got updated...................
Notifying Observers on change...
ElectronicNewsPaper Today's News Content : today's News got updated...................
===================================================
Notifying Observers on change...
PrintNewsPaper Today's News Content : today's News again got updated...................
Notifying Observers on change...
PrintNewsPaper Today's News Content : today's Advertisement got updated...................

2) Using Java built-in API as below:
The java API has one Interface called as ‘java.util.Observer’ and one class called as ‘java.util.Observable’ to provide pub-sub mechanism.

News.java
import java.util.Observable;
public class News extends Observable{   
               private String newsContent;     
               private String advertisement;     
               private int noOfPages;
               public News(String newsContent, String advertisement, int noOfPages) {
                              this.newsContent = newsContent;            
                              this.advertisement = advertisement;          
                              this.noOfPages = noOfPages;     
               }
               public String getNewsContent() {
                              return newsContent;
               }
               public void setNewsContent(String newsContent) {
                              this.newsContent = newsContent;
                              setChanged();
                              notifyObservers(newsContent);
               }
               public String getAdvertisement() {
                              return advertisement;
               }
               public void setAdvertisement(String advertisement) {
                              this.advertisement = advertisement;
               }
               public int getNoOfPages() {
                              return noOfPages;
               }
               public void setNoOfPages(int noOfPages) {
                              this.noOfPages = noOfPages;
               }
}

ElectronicNewsPaper.java
import java.util.Observable;
import java.util.Observer;
public class ElectronicNewsPaper implements Observer {  
               @Override
               public void update(Observable arg0, Object newsContent) {
                              System.out.println("ElectronicNewsPaper Today's News Content : " + (String)newsContent);    
                              //Business-logic to update the Electronic News-Paper
               }
}

PrintNewsPaper.java
import java.util.Observable;
import java.util.Observer;
public class PrintNewsPaper implements Observer {     
               @Override
               public void update(Observable arg0, Object newsContent) {
                              System.out.println("PrintNewsPaper Today's News Content : " + (String)newsContent);   
                              //Business-logic to update the Print News-Paper
               }
}

ObserverClient.java
public class ObserverClient {
               public static void main(String args[]) {
                              PrintNewsPaper printMedia = new PrintNewsPaper();             
                              ElectronicNewsPaper electronicMedia = new ElectronicNewsPaper();
                              News todayNews = new News("today's News........................", "today's Advertisement...........s", 12);    
                              todayNews.addObserver(printMedia);          
                              todayNews.addObserver(electronicMedia);     
                              todayNews.setNewsContent("today's News got updated...................");
                             
                              System.out.println("===================================================");
                              todayNews.deleteObserver(electronicMedia);
                             
                              todayNews.setNewsContent("today's News again got updated...................");
               }
}

Output:-
ElectronicNewsPaper Today's News Content : today's News got updated...................
PrintNewsPaper Today's News Content : today's News got updated...................
===================================================
PrintNewsPaper Today's News Content : today's News again got updated...................
              

Prototype Design Pattern



This is a part of Creational pattern, which helps to create objects as per request. This pattern uses philosophy of cloning to create objects, and we know that two way of cloning is possible, one is shallow cloning, and another is deep cloning. Behavior of both cloning types is different so choose wisely that which type of cloning you need.
You can learn more about cloning here:
When to use Prototype pattern?
               i) If creation of object is complex or costly
               If addition or removal of objects are expected on runtime
               If client should be unaware of the object creation
               If similar object is required as the existing one

One scenario where prototype pattern is used?
               When creating a bank application, and we know that bank transactions need expensive database queries. Transactions would be linked with bank account which may be an individual or group and having their profile with bank. So in this case once the actual object would be created (exactly single object), it may be required further in number of places, so prototype can be used to get the copy of object and finally the modified object can replace the old object.

Example:-
PrototypeClient.java
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
public class PrototypeClient {
               public static void main( String[] args ) {
                              Shoes xyz = Factory.makeObject("Sport");
                              xyz.wear();
               }
}


Shoes.java
abstract class Shoes implements Serializable, Cloneable{  
               private static final long serialVersionUID = -1937047519230746677L;
               abstract void wear();
               public Object shallowCloning() throws CloneNotSupportedException    {
                              return this.clone();
               }
               public Shoes deepCloning() throws IOException, ClassNotFoundException{
                              //Serialization of object
                              ByteArrayOutputStream bos = new ByteArrayOutputStream();
                              ObjectOutputStream out = new ObjectOutputStream(bos);
                              out.writeObject(this);
                              //De-serialization of object
                              ByteArrayInputStream bis = new   ByteArrayInputStream(bos.toByteArray());
                              ObjectInputStream in = new ObjectInputStream(bis);
                              Shoes clonedShoes = (Shoes) in.readObject();
                              return clonedShoes;
               }
}

SportShoes.java
class SportShoes extends Shoes {
               private static final long serialVersionUID = 440347043243434494L;
               public String toString() {
                              return "SportShoes";
               }
               @Override
               public void wear() {
                              //some SportShoes specific code to wear
                              System.out.println("I am wearing " + toString());
               }
}

CasualShoes.java
class CasualShoes extends Shoes {
               private static final long serialVersionUID = -6493171299609719559L;
               public String toString() {
                              return "CasualShoes";
               }
               @Override
               public void wear() {
                              //some CasualShoes specific code to wear
                              System.out.println("I am wearing " + toString());
               }
}

FormalShoes.java
class FormalShoes extends Shoes {
               private static final long serialVersionUID = -5670125744755511170L;
               public String toString() {
                              return "FormalShoes";
               }
               @Override
               public void wear() {
                              //some FormalShoes specific code to wear
                              System.out.println("I am wearing " + toString());
               }
}
Factory.java
class Factory {
               private static Map<String, Object> prototypes = new HashMap<String, Object>();
               static {
                              prototypes.put( "Sport",   new SportShoes() );
                              prototypes.put( "Casual",  new CasualShoes() );
                              prototypes.put( "Formal", new FormalShoes() );
               }
               public static Shoes makeObject(String shoesType) {
                              Shoes shoes = (Shoes)prototypes.get(shoesType);
                              //deep cloning (using in-memory)
                              try {
                                             Shoes deepClonedShoes = shoes.deepCloning();
                                             System.out.println("Deep-Cloned Shoes ========== "+deepClonedShoes);
                              } catch (IOException e) {
                                             e.printStackTrace();
                              } catch (ClassNotFoundException e) {
                                             e.printStackTrace();
                              }
                              //Shallow cloning
                              Shoes shallowClonedShoes = null;
                              try {
                                             shallowClonedShoes = (Shoes) shoes.shallowCloning();
                              } catch (CloneNotSupportedException e) {
                                             e.printStackTrace();
                              }
                              System.out.println("Shallow-Cloned Shoes ========== " +shallowClonedShoes );
                              return shallowClonedShoes;
               }
}

Output:
 Deep-Cloned Shoes ========== SportShoes
Shallow-Cloned Shoes ========== SportShoes
I am wearing SportShoes