How to avoid large if-statements and instanceof

Solution 1:

An elegant way of avoiding instanceof without inventing some new artificial method in the base class (with a non-descriptive name such as performAction or doWhatYouAreSupposedToDo) is to use the visitor pattern. Here is an example:

Animal

import java.util.*;

abstract class Animal {
    String name;

    public Animal(String name) {
        this.name = name;
    }

    public abstract void accept(AnimalVisitor av);  // <-- Open up for visitors.

}

Lion and Deer

class Lion extends Animal {
    public Lion(String name) {
        super(name);
    }
    public void roar() {
        System.out.println("Roar");
    }

    public void accept(AnimalVisitor av) {
        av.visit(this);                            // <-- Accept and call visit.
    }
}


class Deer extends Animal {

    public Deer(String name) {
        super(name);
    }

    public void runAway() {
        System.out.println("Running...");
    }

    public void accept(AnimalVisitor av) {
        av.visit(this);                            // <-- Accept and call visit.
    }

}

Visitor

interface AnimalVisitor {
    void visit(Lion l);
    void visit(Deer d);
}

class ActionVisitor implements AnimalVisitor {

    public void visit(Deer d) {
        d.runAway();
    }

    public void visit(Lion l) {
        l.roar();
    }
}

TestAnimals

public class TestAnimals {
    public static void main(String[] args) {
        Animal lion = new Lion("Geo");
        Animal deer1 = new Deer("D1");
        Animal deer2 = new Deer("D2");

        List<Animal> li = new ArrayList<Animal>();
        li.add(lion);
        li.add(deer1);
        li.add(deer2);
        for (Animal a : li)
            a.accept(new ActionVisitor());         // <-- Accept / visit.
    }
}

Solution 2:

Animal

public abstract class Animal {
 String name;

 public Animal(String name) {
  this.name = name;
 }

 public abstract void exhibitNaturalBehaviour();

}

Lion

public class Lion extends Animal {

 public Lion(String name) {
  super(name);
 }

 public void exhibitNaturalBehaviour() {
  System.out.println("Roar");
 }
}

Deer

public class Deer extends Animal {

 public Deer(String name) {
  super(name);
 }

 public void exhibitNaturalBehaviour() {
  System.out.println("Running...");
 }

}

TestAnimals

public class TestAnimals {
 public static void main(String[] args) {

  Animal[] animalArr = {new Lion("Geo"), new Deer("D1"), new Deer("D2")};
  for (Animal a : animalArr) {
     a.exhibitNaturalBehaviour();    
  }

 }
}

Solution 3:

Yes provide a method called action() in abstract class , implement it in both of the child class, one will roar other will runaway