Visitor Design Pattern real world example in Java

Visitor Design Pattern real world example in Java


In this post we will see when to use visitor design pattern and the real life example of visitor design pattern in Java.

Scenario for understanding Visitor Design Pattern.

Consider a scenario below,

You own a small supermarket selling items of multiple category ranging from Electronics, Hardware, Plastic, Packaged food, Fresh fruit etc.
  • Supermarket have return policy based on the item category.
  • Supermarket provide discounts based on the item category.
  • Supermarket have different shipping vendor based on item category. (say you purchased an item from e-commerce company like Amazon and now you want to return it. In some countries, they arrange a person to visit your place for picking the item. In some countries, they email you pre-paid shipping label from standard transportation companies like Canada post, UPS etc and you have to pack the item, stick the shipping label and handover to the shipping provider.)
too much explanation... :) lets look into how above scenario can be designed without using visitor design pattern and then we will see benefits of visitor pattern and how it helps in maintaining Open/Closed and Single Responsibility Principle.


For each different category we have to apply different rules in terms of discounts, return policy and shipping vendor.

Problem without Visitor Design Pattern.


We have multiple product category and each have the name, discount, return policy and shipping vendor. we would design something like below,

interface ProductCategory {
String getName();
int discount();
String shippingVendor();
int returnPolicy();
}

class Plastic implements ProductCategory {
@Override
public String getName() {
return "Plastic";
}

@Override
public int discount() {
return 5;
}

@Override
public String shippingVendor() {
return "UPS";
}

@Override
public int returnPolicy() {
return 30;
}
}

class Electronics implements ProductCategory {
@Override
public String getName() {
return "Electronics";
}

@Override
public int discount() {
return 10;
}

@Override
public String shippingVendor() {
return "Canada Post";
}

@Override
public int returnPolicy() {
return 60;
}
}

Now, Imagine you have to add one more rule say packaging type for each category. what we will do is modify the interface to add one more method, 

interface ProductCategory {
String getName();
int discount();
String shippingVendor();
int returnPolicy();
String packingType(); //added
}
You have to modify all the implementation to have this packing type. which is against Open/Closed principle.

Also, responsibility like Discounts, return policy are segregated into each implementation and not at one place.
  
Lets see the sample implementation with Visitor Design pattern now,

Visitor Design Pattern.

With Visitor Design pattern, all such rules that can be applied to each product category is separated from category itself.

Example: Electronics category will not have any implementation details for discounts, return policy, shipping vendor etc as those are the rules that could be added/removed to each category and could change.

so what we would be doing is to allow Electronics category having a visitor called ProductCategoryVisitor (which could be of type DiscountVisitor, ShippingVendorVisitor, ReturnPolicyVisior etc).  

package fresh.armaan;

public class VisitorDesignPattern {

public static void main(String[] args) {
ProductCategoryVisitor discountVisitor = new DiscountVisitor();
ProductCategoryVisitor returnPolicyVisitor = new ReturnPolicyVisitor();

//Plastic
ProductCategory plasticCategory = new Plastic();
System.out.println("Category Name : " + plasticCategory.getName());
System.out.println("Discounts on Plastic Category : " + plasticCategory.visit(discountVisitor) + "%");
System.out.println("Return Policy on Plastic Category : " + plasticCategory.visit(returnPolicyVisitor) + " days");

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

//Electronics
ProductCategory electronicsCategory = new Electronics();
System.out.println("Category Name : " + electronicsCategory.getName());
System.out.println("Discounts on Electronics Category : " + electronicsCategory.visit(discountVisitor) + "%");
System.out.println("Return Policy on Electronics Category : " + electronicsCategory.visit(returnPolicyVisitor) + " days");
}
}

interface ProductCategory {
String getName();
String visit(ProductCategoryVisitor visitor);
}

class Plastic implements ProductCategory {
@Override
public String getName() {
return "Plastic";
}

@Override
public String visit(ProductCategoryVisitor visitor) {
return visitor.visit(this);
}
}

class Electronics implements ProductCategory {
@Override
public String getName() {
return "Electronics";
}

@Override
public String visit(ProductCategoryVisitor visitor) {
return visitor.visit(this);
}
}

interface ProductCategoryVisitor {
String visit(Electronics electronics);
String visit(Plastic plastic);
}

class DiscountVisitor implements ProductCategoryVisitor {

@Override
public String visit(Electronics electronics) {
return "10";
}

@Override
public String visit(Plastic plastic) {
return "5";
}
}

class ReturnPolicyVisitor implements ProductCategoryVisitor {

@Override
public String visit(Electronics electronics) {
return "60";
}

@Override
public String visit(Plastic plastic) {
return "30";
}
}
 
Output:
Category Name : Plastic
Discounts on Plastic Category : 5%
Return Policy on Plastic Category : 30 days
------------------
Category Name : Electronics
Discounts on Electronics Category : 10%
Return Policy on Electronics Category : 60 days
Use visitor pattern when you have a fairly stable class hierarchy (like in our example we have product category Electronics, Plastic etc which changes but not very frequently), but have changing requirements of what needs to be done with that hierarchy (in our example each product category have discounts, return policy, shipping vendor and so on and that could add/remove/change very often), in that case visitor pattern is helpful.

You may also like to see


Advanced Java Multithreading Interview Questions & Answers

Type Casting Interview Questions and Answers In Java?

Exception Handling Interview Question-Answer

Method Overloading - Method Hiding Interview Question-Answer

How is ambiguous overloaded method call resolved in java?

Method Overriding rules in Java

Interface interview questions and answers in Java


Enjoy !!!! 
If you find any issue in post or face any error while implementing, Please comment.

When to use Builder design pattern.

Builder Design Pattern.


Builder Design pattern is used to simplify the creation of complex Immutable object.

In simple words, we should use builder design pattern when a class have multiple properties, some of which are optional and some mandatory for an object creation that is constructor or static factories of such a class would require more than 4 to 5 parameters.
Builder design pattern in java
When to use Builder Design Pattern

Purpose of the Builder Design Pattern


Consider a class with multiple fields, Example: Pizza, Burger, Assembled Car, Computer etc, object creation of such class(Pizza) is complex due to multiple constructors required with some mandatory fields(like pizza size, bread type) and some optional(like pizza toppings cheese, olive, pepper etc).

Problem without Builder Pattern, 

Approach 1: Telescoping Constructor

For creating a object of such complex classes, it would require multiple constructors(Telescoping Constructor) each taking mandatory parameters with a new optional parameter as shown below,

public Pizza (int size, boolean cheese){ ... }
public Pizza (int size, boolean cheese, boolean olive){ ... } 
public Pizza (int size, boolean cheese, boolean olive, boolean pepper){ ... } 
public Pizza (int size, boolean cheese, boolean olive, boolean pepper, boolean onion){ ... }
Telescoping Constructor: A class with many constructors, where each constructor calls a more specific constructor in the hierarchy, which has more parameters than itself, providing default values for the extra parameters. The next constructor does the same until there is no left.
Problem: We can use Telescoping constructors in this situation but a problem with this pattern is that once constructors start taking more than 4 to 5 parameters, It becomes difficult to maintain and remember the required order of the parameters, also it brings more complexity for the caller of the constructor as which one to call in a given situation.

Approach 2: Setter method

One way of creating the object is to use setter method approach to set the properties of object step by step.
Pizza pizza = new Pizza(6);
pizza.setCheese(true);
pizza.setOlive(true);
pizza.setPepper(true);

Problem: we cannot use setter method approach here because with setter method, object could be modify after it is created using setter call and would no longer remain immutable.

Builder Pattern in Rescue

To avoid above problems in a situation where we have complex constructor, large number of parameters and need object Immutability, we use builder design pattern which separates the construction of a complex object from its representation.

Pizza.java
package javabypatel;

public class Pizza {
    private int size;
    private BreadType breadType;

    private boolean cheese;
    private boolean olive;
    private boolean pepper;

    public Pizza (PizzaBuilder pizzaBuilder) {
        this.size = pizzaBuilder.size;
        this.breadType = pizzaBuilder.breadType;

        this.cheese = pizzaBuilder.cheese;
        this.olive = pizzaBuilder.olive;
        this.pepper = pizzaBuilder.pepper;
    }

    public static class PizzaBuilder {
        //Mandatory Parameters
        private int size;
        private BreadType breadType;

        //Optional Parameters
        private boolean cheese;
        private boolean olive;
        private boolean pepper;

        public PizzaBuilder(int size, BreadType breadType) {
            this.size = size;
            this.breadType = breadType;
        }

        public PizzaBuilder withCheese(boolean cheese) {
            this.cheese = cheese;
            return this;
        }
        public PizzaBuilder withOlive(boolean olive) {
            this.olive = olive;
            return this;
        }
        public PizzaBuilder withPepper(boolean pepper) {
            this.pepper = pepper;
            return this;
        }

        public Pizza build() {
            return new Pizza(this);
        }
    }
}

enum BreadType {
    THIN_CRUST,
    THICK_CRUST,
    FLAT_BREAD;
}

class Main {
    public static void main(String[] args) {
        Pizza pizza = new Pizza.PizzaBuilder(6, BreadType.THICK_CRUST)
                .withCheese(true)
                .withOlive(true)
                .build();
        System.out.println(pizza);
    }
}

Advantages of Builder Design Pattern


1. Complex object construction become more readable and easy.
2. No need to pass optional parameters in creating the object.

Disadvantages of Builder Design Pattern


1. Builder pattern requires creating a separate Builder class for each different Type.
2. It creates more code.

Builder Design Pattern used in JDK API.


java.lang.StringBuilder class is a Builder for String class. 
String str = new StringBuilder("Hello").appeend("world").toString();

You may also like to see


Command Design Pattern

Observer Design Pattern

Adapter Design Pattern

Decorator Design Pattern

Enjoy !!!! 
If you find any issue in post or face any error while implementing, Please comment.

Command Design Pattern.

Command Design Pattern.


Command Design pattern is used to decouple Sender and Receiver.
Sender is totally unaware of Receiver's interface and Receiver is unaware of Sender.
Sender and Receiver communicates using command.



Command Design Pattern Example In Java.



Receiver.java
abstract class Receiver{
 public abstract void append(String data);
 public abstract String getContent();
 public abstract void copy(String copyData);
 public abstract void paste();
 public abstract void cut(int startIndex, int endIndex);
 public abstract void setContent(String content);
 public abstract String getName();
}

Notepad.java
class Notepad extends Receiver{
 private StringBuilder content;
 private String copyData;

 public Notepad(String init) {
  content = new StringBuilder(init);
 }
 public void append(String data){
  content.append(data);
 }
 public String getContent() {
  return content.toString();
 }
 public void copy(String copyData){
  this.copyData = copyData;
 }
 public void paste(){
  content.append(copyData);
 }
 public void cut(int startIndex, int endIndex){
  content = content.delete(startIndex, endIndex);
 }
 public void setContent(String content) {
  this.content = new StringBuilder(content);
 }
 public String getName() {
  return "Notepad";
 }
}

Wordpad.java
class Wordpad extends Receiver{
 private StringBuilder content;
 private String copyData;

 public Wordpad(String init) {
  content = new StringBuilder(init);
 }
 public void append(String data){
  content.append(data);
 }
 public String getContent() {
  return content.toString();
 }
 public void copy(String copyData){
  this.copyData = copyData;
 }
 public void paste(){
  content.append(copyData);
 }
 public void cut(int startIndex, int endIndex){
  content = content.delete(startIndex, endIndex);
 }
 public void setContent(String content) {
  this.content = new StringBuilder(content);
 }
 public String getName() {
  return "Wordpad";
 }
}

Command.java
interface Command{
 public void execute();
 public void redo();
}

Undo.java
interface Undo{
 public void undo();
}

CopyCommand.java
class CopyCommand implements Command{ 
 private String copiedData = "";

 public CopyCommand(String copiedData) {
  this.copiedData=copiedData;
 }
 public void execute() {
  System.out.println("Successfully copied: "+copiedData);
 }
 public void redo() {
  execute();
 }
 public String getCopiedData() {
  return copiedData;
 }
}

PasteCommand.java
class PasteCommand implements Command, Undo{
 private Receiver receiver=null;
 private String contentToPaste="";
 private String previousContent="";

 public PasteCommand(Receiver receiver, String contentToPaste) {
  this.receiver=receiver;
  this.contentToPaste=contentToPaste;
 }
 public void execute() {
  previousContent = receiver.getContent();
  receiver.copy(contentToPaste);
  receiver.paste();
  System.out.println("Data Pasted successfully in "+ receiver.getName() +" new content is : "+receiver.getContent());
 }
 public void undo() {
  receiver.setContent(previousContent);
  System.out.println("Done undoing and receiver "+ receiver.getName() +" data is : "+receiver.getContent());
 }
 public void redo() {
  execute();
 }
}
CutCommand.java
class CutCommand implements Command, Undo{ 
 private Receiver receiver=null;
 private String previousContent=null;
 private int startIndex=0;
 private int endIndex=0;

 public CutCommand(Receiver receiver, int startIndex, int endIndex) {
  this.receiver = receiver;
  this.startIndex = startIndex;
  this.endIndex = endIndex;
 }
 public void execute() {
  previousContent = receiver.getContent();
  receiver.cut(startIndex, endIndex);
  System.out.println("Data Cut successfully in "+ receiver.getName() +" new content is : "+receiver.getContent());
 }
 public void undo() {
  receiver.setContent(previousContent);
  System.out.println("Done undoing and receiver "+ receiver.getName() +" data is : "+receiver.getContent());
 }
 public void redo() {
  execute();
 }
}

CommandManager.java
class CommandManager{
 private Stack<Command> redoCommandStack = null;
 private Stack<Command> undoCommandStack = null;

 public CommandManager() {
  undoCommandStack = new Stack<Command>();
  redoCommandStack = new Stack<Command>();
 }

 public void setCommand(Command command) {
  undoCommandStack.add(command);
 }
 public void execute(){
  undoCommandStack.peek().execute();
 }
 public void undo(){
  if(!undoCommandStack.isEmpty()){
   redoCommandStack.push(undoCommandStack.peek());
   ((Undo)(undoCommandStack.pop())).undo();

  }else{
   System.out.println("Nothing to undo");
  }
 }
 public void redo(){
  if(!redoCommandStack.isEmpty()){
   redoCommandStack.pop().redo();
  }else{
   System.out.println("Nothing to redo");
  }
 }
}

CommandDesignPattern.java
public class CommandDesignPattern {

 public static void main(String[] args) {

  CommandManager commandManager = new CommandManager();
  Notepad notepadReceiver = new Notepad("Notepad, how are you?");
  Wordpad wordpadReceiver = new Wordpad("Wordpad, how are you?");

  //COPY
  Command copyCommand2 = new CopyCommand("good");
  commandManager.setCommand(copyCommand2);
  commandManager.execute();

  //PASTE
  Command pasteCommand = new PasteCommand(wordpadReceiver, ((CopyCommand)copyCommand2).getCopiedData());
  commandManager.setCommand(pasteCommand);
  commandManager.execute();

  //CUT
  Command copyCommand1 = new CutCommand(notepadReceiver, 2, 5);
  commandManager.setCommand(copyCommand1);
  commandManager.execute();

  //UNDO
  System.out.println("\nUndo::");
  commandManager.undo();
  System.out.println("Undo::");
  commandManager.undo();

  //REDO
  System.out.println("\nRedo::");
  commandManager.redo();
  System.out.println("Redo::");
  commandManager.redo();
 }
}


 

Real World Example.


Resturant is a classic example of Command Pattern.
Customer(Invoker) is not aware of Chef(Receiver) and they communicate via Waiter(Command Manager) by giving Menu Name(Commands) to them.
Customer doesn't need to know how to communicate directly with Chef.

Command Design Pattern used in JDK API.


java.lang.Runnable interface exhibits Command design pattern.

Thread pools
  • A typical, general-purpose thread pool class might have a public addTask() method that adds a work item to an internal queue of tasks waiting to be done. 
  • It maintains a pool of threads that execute commands from the queue. 
  • The items in the queue are command objects. 
  • Typically these objects implement a common interface such as java.lang.Runnable that allows the thread pool to execute the command even though the thread pool class itself was written without any knowledge of the specific tasks 

You may also like to see


Observer Design Pattern

When to use Builder design pattern

Adapter Design Pattern

Decorator Design Pattern

Enjoy !!!! 

If you find any issue in post or face any error while implementing, Please comment.

Decorator Design Pattern

Decorator Design Pattern.


Decorator Design Pattern allows class to extend its functionalities dynamically without changing the actual class implementation.


Decorator Design Pattern Example In Java.

Say we are opening a Cake shop and planning to sell many flavours of cake.


Also, custom cake order will be accepted as per Customer needs. 
How to design a class for this purpose. Decorator pattern is helpful for this kind of requirement.


Cake.java
interface Cake{
 void flavour();
 int getAmount();
}
BasicCake.java
class BasicCake implements Cake{
 @Override
 public void flavour() {
  System.out.println("Basic Cake");
 }

 @Override
 public int getAmount() {
  return 50;
 }
}
CakeDecorator.java (It is made abstract because it is helper class and object of only implementations of it is possible)
abstract class CakeDecorator implements Cake{
 private Cake cake;
 
 public CakeDecorator(Cake cake) {
  this.cake = cake;
 }
 
 @Override
 public void flavour() {
  cake.flavour();
 }
 
 @Override
 public int getAmount() {
  return cake.getAmount();
 }
}
VanillaCake.java
class VanillaCake extends CakeDecorator{
 
 public VanillaCake(Cake cake) {
  super(cake);
 }
 
 @Override
 public void flavour() {
  super.flavour();
  System.out.println("Adding Vanilla falvour");
 }
 
 @Override
 public int getAmount() {
  return super.getAmount() + 10;
 }
}
StrawberyCake.java
class StrawberyCake extends CakeDecorator{
 
 public StrawberyCake(Cake cake) {
  super(cake);
 }
 
 @Override
 public void flavour() {
  super.flavour();
  System.out.println("Adding Strawberry falvour");
 }
 
 @Override
 public int getAmount() {
  return super.getAmount() + 10;
 }
}
DecoratorDesignPattern.java
public class DecoratorDesignPattern {

 public static void main(String[] args) {
  VanillaCake vanillaStrawberryCake = new VanillaCake(new StrawberyCake(new BasicCake()));
  vanillaStrawberryCake.flavour();
  System.out.println(vanillaStrawberryCake.getAmount());
 }
}


Decorator Design Pattern used in JDK API.


Base class
java.io.Reader;
java.io.InputStream;

Decorators:
java.io.BufferedReader(java.io.Reader);
java.io.FileReader(java.io.Reader);

java.io.DataInputStream(
java.io.InputStream)
java.io.BufferedInputStream
(java.io.InputStream)  

Constructor of BufferedReader takes parameter as Reader class and add more few more features like readLine() method, which is specific to BufferedReader class only.

Eg:  BufferedReader in = new BufferedReader(new FileReader("foo.in"));
Eg:  DataInputStream input = new DataInputStream(new ZipInputStream(new

        FileInputStream("foo.zip")));
 

You may also like to see


Observer Design Pattern

When to use Builder design pattern

Adapter Design Pattern

Command Design Pattern

Enjoy !!!! 

If you find any issue in post or face any error while implementing, Please comment.

Observer Design Pattern

Observer Design Pattern.


Observer Design Pattern is used to notify interested Observers on any change to subject.


Observer Design Pattern Example In Java.

In our example we will notify SocialMediaNotifier and SubscribedUserNotifier whenever a new post is published on JavaByPatel blog.  
SocialMediaNotifier and SubscribedUserNotifier will update post to necessary places. 

Observer : SocialMediaNotifier, SubscribedUserNotifier 
Subject : Blog post.


Observer.java
interface Observer{
 void notify(String post);
}
SocialMediaNotifier.java
class SocialMediaNotifier implements Observer{
 @Override
 public void notify(String post) {
  System.out.println("SocialMediaNotifier: New post published :"+post);
 }
}
SubscribedUserNotifier.java
class SubscribedUserNotifier implements Observer{
 @Override
 public void notify(String post) {
  System.out.println("SubscribedUserNotifier: New post published :"+post);
 }
}
Subject.java
interface Subject{
 void addObserver(Observer observer);
 void removeObserver(Observer observer);
 void notifyObservers();
}
JavaByPatelBlogPost.java
class JavaByPatelBlogPost implements Subject{
 private String post;
 private List<Observer> listOfObserver = new ArrayList<Observer>();
 
 @Override
 public void addObserver(Observer observer) {
  listOfObserver.add(observer);
 }

 @Override
 public void removeObserver(Observer observer) {
  listOfObserver.remove(observer);
 }

 @Override
 public void notifyObservers() {
  for (Observer observer : listOfObserver) {
   observer.notify(post);
  }
 }
 
 public void newPost(String post) {
  this.post = post;
  notifyObservers();
 }
}

ObserverDesignPattern.java
public class ObserverDesignPattern {

 public static void main(String[] args) {
  SocialMediaNotifier socialMediaNotifier = new SocialMediaNotifier();
  SubscribedUserNotifier subscribedUserNotifier = new SubscribedUserNotifier();
  
  JavaByPatelBlogPost blogPost = new JavaByPatelBlogPost();
  blogPost.addObserver(socialMediaNotifier);
  blogPost.addObserver(subscribedUserNotifier);
  
  blogPost.newPost("HelloPost");
 }
}

You may also like to see


Decorator Design Pattern

Adapter Design Pattern

When to use Builder design pattern

Command Design Pattern

Enjoy !!!! 

If you find any issue in post or face any error while implementing, Please comment.

Adapter Design Pattern

Adapter Design Pattern.


Adapter Design Pattern is used to make in-compatible interfaces compatible.



Adapter Design Pattern Example In Java.

We have Socket which charges Apple Mobile and we want same Socket to be used for Samsung Mobile as well, We will make socket compatible.  

Apple.java
interface Apple{
 void charge();
}
AppleImpl.java
class AppleImpl implements Apple{
 
 @Override
 public void charge() {
  System.out.println("Charging Apple Mobile...");
 }
}
SocketForAppleMobile.java
class SocketForAppleMobile{
 public static void charge(Apple apple){
  System.out.println("It is not correct but say: Start Electricity at home");
  apple.charge();
  System.out.println("It is not correct but say: End Electricity at home");
 }
}
Samsung.java
interface Samsung{
 void charge();
}
SamsumgImpl.java
class SamsumgImpl implements Samsung{
 
 @Override
 public void charge() {
  System.out.println("Charging Samsung Mobile...");
 }
}
AppleSamsungAdapter.java
class AppleSamsungAdapter implements Apple{
 
 private Samsung samsung;
 
 public AppleSamsungAdapter(Samsung samsung) {
  this.samsung = samsung;
 }
 
 @Override
 public void charge() {
  samsung.charge();
 }
}
AdapterDesignPattern.java
public class AdapterDesignPattern {

 public static void main(String[] args) {
  Apple appleMobile = new AppleImpl();
  SocketForAppleMobile.charge(appleMobile);
  
  Samsung samsungMobile = new SamsumgImpl();
  //SocketForAppleMobile.charge(samsungMobile); //It will not accept Samsung charger
  
  AppleSamsungAdapter appleSamsungMobile = new AppleSamsungAdapter(samsungMobile);
  SocketForAppleMobile.charge(appleSamsungMobile); //It will charge now..
 }
}

Decorator Design Pattern

When to use Builder design pattern

Observer Design Pattern

Command Design Pattern

Enjoy !!!! 

If you find any issue in post or face any error while implementing, Please comment.