Friday 25 November 2016

Design Patterns : Tutorial 2

Visitor Design Pattern

public interface ItemElement {

       public int accept(ShoppingCartVisitor visitor);
}

public class Book implements ItemElement {

       private int price;
       private String isbnNumber;

       public Book(int cost, String isbn){
              this.price=cost;
              this.isbnNumber=isbn;
       }

       public int getPrice() {
              return price;
       }

       public String getIsbnNumber() {
              return isbnNumber;
       }

       @Override
       public int accept(ShoppingCartVisitor visitor) {
              return visitor.visit(this);
       }
}

public class Fruit implements ItemElement {

       private int pricePerKg;
       private int weight;
       private String name;

       public Fruit(int priceKg, int wt, String nm){
              this.pricePerKg=priceKg;
              this.weight=wt;
              this.name = nm;
       }

       public int getPricePerKg() {
              return pricePerKg;
       }

       public int getWeight() {
              return weight;
       }

       public String getName(){
              return this.name;
       }

       @Override
       public int accept(ShoppingCartVisitor visitor) {
              return visitor.visit(this);
       }
}

public interface ShoppingCartVisitor {

       int visit(Book book);
       int visit(Fruit fruit);
}

public class ShoppingCartVisitorImpl implements ShoppingCartVisitor {

       @Override
       public int visit(Book book) {
              int cost=0;
              //apply 5$ discount if book price is greater than 50
              if(book.getPrice() > 50){
                     cost = book.getPrice()-5;
              }else cost = book.getPrice();
              System.out.println("Book ISBN::"+book.getIsbnNumber() + " cost ="+cost);
              return cost;
       }

       @Override
       public int visit(Fruit fruit) {
              int cost = fruit.getPricePerKg()*fruit.getWeight();
              System.out.println(fruit.getName() + " cost = "+cost);
              return cost;
       }
}

public class ShoppingCartClient {

       public static void main(String[] args) {
              ItemElement[] items = new ItemElement[]{new Book(20, "1234"),new Book(100, "5678"),
                           new Fruit(10, 2, "Banana"), new Fruit(5, 5, "Apple")};

              int total = calculatePrice(items);
              System.out.println("Total Cost = "+total);
       }

       private static int calculatePrice(ItemElement[] items) {
              ShoppingCartVisitor visitor = new ShoppingCartVisitorImpl();
              int sum=0;
              for(ItemElement item : items){
                     sum = sum + item.accept(visitor);
              }
              return sum;
       }

}

Output:
Book ISBN::1234 cost =20
Book ISBN::5678 cost =95
Banana cost = 20
Apple cost = 25
Total Cost = 160

Benefits of Visitor pattern:

The benefit of this pattern is that if the logic of operation changes, then we need to make change only in the visitor implementation rather than doing it in all the item classes.

Another benefit is that adding a new item to the system is easy, it will require change only in visitor interface and implementation and existing item classes will not be affected.

Composite Design Pattern

This pattern is used to populate a tree like structure. The real example for this can be shown as an hierarchy in company where there is CEO under him the GM then the Manager and finally the Employee. This consists of three parts.

  • Component
    • declares interface for objects in composition.
    • implements deafault behaviour for the interface common to all classes as appropriate.
    • declares an interface for accessing and managing its child components.
  • Leaf
    • represents leaf objects in the composition.A leaf has no children.
    • defines behaviour for primitive objects in the composition.
  • Composite
    • defines behaviour for components having children.
    • stores child components.
    • implements child related operations in the component interface.
  • Client
    • manipulates objects in the composition through the component interface.

public interface Employee {

     public void add(Employee employee);

     public void remove(Employee employee);

     public Employee getChild(int i);

     public String getName();

     public double getSalary();

     public void print();

}

public class Manager implements Employee{


 private String name;

 private double salary;


 public Manager(String name,double salary){

  this.name = name;

  this.salary = salary;

 }



 List<Employee> employees = new ArrayList<Employee>();

 public void add(Employee employee) {

    employees.add(employee);

 }


 public Employee getChild(int i) {

  return employees.get(i);

 }


 public String getName() {

  return name;

 }


 public double getSalary() {

  return salary;

 }


 public void print() {

  System.out.println("-------------");

  System.out.println("Name ="+getName());

  System.out.println("Salary ="+getSalary());

  System.out.println("-------------");



  Iterator<Employee> employeeIterator = employees.iterator();

    while(employeeIterator.hasNext()){

     Employee employee = employeeIterator.next();

     employee.print();

    }

 }


 public void remove(Employee employee) {

  employees.remove(employee);

 }

}

public class Developer implements Employee{


    private String name;

    private double salary;


    public Developer(String name,double salary){

        this.name = name;

        this.salary = salary;

    }

    public void add(Employee employee) {

        //this is leaf node so this method is not applicable to this class.

    }


    public Employee getChild(int i) {

        //this is leaf node so this method is not applicable to this class.

        return null;

    }


    public String getName() {

        return name;

    }


    public double getSalary() {

        return salary;

    }


    public void print() {

        System.out.println("-------------");

        System.out.println("Name ="+getName());

        System.out.println("Salary ="+getSalary());

        System.out.println("-------------");

    }


    public void remove(Employee employee) {

        //this is leaf node so this method is not applicable to this class.

    }


}

public class CompositeDesignPatternMain {


 public static void main(String[] args) {

  Employee emp1=new Developer("John", 10000);

  Employee emp2=new Developer("David", 15000);

  Employee manager1=new Manager("Daniel",25000);

  manager1.add(emp1);

  manager1.add(emp2);

  Employee emp3=new Developer("Michael", 20000);

  Manager generalManager=new Manager("Mark", 50000);

  generalManager.add(emp3);

  generalManager.add(manager1);

  generalManager.print();

 }

}


Observer Design Pattern

This updates the Observers which are registered on the changes of the values. The best example of this can be the waiting and notifying of threads.
PFB the example.


public interface Observer {

       public void update(float temp,float humidity,float pressure);

}

public interface Subject {

       public void registerObservers(Observer o);
       public void removeObservers(Observer o);
       public void notifyObservers();

}

public interface DisplayElement {

       public void display();

}

public class WeatherData implements Subject {

       private ArrayList<Observer> observers;
       private float temperature;
       private float humidity;
       private float pressure;

       public WeatherData(){
              observers = new ArrayList<Observer>();
       }

       public void notifyObservers(){
              for(Observer observer:observers){
                     observer.update(temperature, humidity, pressure);
              }
       }

       public void measurementsChanged(){
              notifyObservers();
       }

       public void setMeasurements(float temperature,float humidity,float pressure){
              this.temperature = temperature;
              this.humidity = humidity;
              this.pressure = pressure;
              measurementsChanged();
       }

       @Override
       public void registerObservers(Observer o) {
              observers.add(o);

       }

       @Override
       public void removeObservers(Observer o) {
              int i = observers.indexOf(o);
              if(i >= 0){
                     observers.remove(i);
              }
       }

}


public class CurrentConditionsDisplay implements Observer,DisplayElement {

       private float temperature;
       private float humidity;
       private Subject weatherData;

       public CurrentConditionsDisplay(Subject weatherData){
              this.weatherData = weatherData;
              weatherData.registerObservers(this);
       }

       @Override
       public void display() {
              System.out.println("Current Conditions: "+temperature + "F degrees and "
                           + humidity + "% humidity");

       }

       @Override
       public void update(float temp, float humidity, float pressure) {
              this.temperature = temperature;
              this.humidity = humidity;
              display();
       }

}

public class WeatherStation {

       public static void main(String[] args) {
              WeatherData weatherData = new WeatherData();

              CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(weatherData);

              weatherData.setMeasurements(80, 65, 30.4f);
              weatherData.setMeasurements(82, 70, 29.2f);
              weatherData.setMeasurements(78, 90, 29.2f);

       }

}

The Output of this is:

Current Conditions: 0.0F degrees and 65.0% humidity
Current Conditions: 0.0F degrees and 70.0% humidity
Current Conditions: 0.0F degrees and 90.0% humidity



No comments:

Post a Comment