Reputation: 13799
Animal
public abstract class Animal {
String name;
public Animal(String name) {
this.name = name;
}
}
Lion
public class Lion extends Animal {
public Lion(String name) {
super(name);
// TODO Auto-generated constructor stub
}
public void roar() {
System.out.println("Roar");
}
}
Deer
public class Deer extends Animal {
public Deer(String name) {
super(name);
}
public void runAway() {
System.out.println("Running...");
}
}
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) {
if (a instanceof Lion) {
Lion l = (Lion) a;
l.roar();
}
if (a instanceof Deer) {
Deer l = (Deer) a;
l.runAway();
}
}
}
}
Is there a better way to iterate through the list without having to cast ?In the above case it seem's ok but if you have many extensions of the base class then we'll need that many if block too.Is there a design pattern or principle to address this problem ?
Upvotes: 20
Views: 5498
Reputation: 421290
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.
}
}
Upvotes: 35
Reputation: 8692
It turns out that instanceof is faster than the visitor pattern presented above; I think this should make us question, is the visitor pattern really more elegant than instanceof when it's doing the same thing more slowly with more lines of code?
Here's my test. I compared 3 methods: the visitor pattern above, instanceof, and an explicit type field in Animal.
OS: Windows 7 Enterprise SP1, 64-bit
Processor: Intel(R) Core(TM) i7 CPU 860 @ 2.80 GHz 2.93 GHz
RAM: 8.00 GB
JRE: 1.7.0_21-b11, 32-bit
import java.util.ArrayList;
import java.util.List;
public class AnimalTest1 {
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);
int reps = 10000000;
long start, elapsed;
start = System.nanoTime();
for (int i = 0; i < reps; i++) {
for (Animal a : li)
a.accept(new ActionVisitor()); // <-- Accept / visit.
}
elapsed = System.nanoTime() - start;
System.out.println("Visitor took " + elapsed + " ns");
start = System.nanoTime();
for (int i = 0; i < reps; i++) {
for (Animal a : li) {
if (a instanceof Lion) {
((Lion) a).roar();
} else if (a instanceof Deer) {
((Deer) a).runAway();
}
}
}
elapsed = System.nanoTime() - start;
System.out.println("instanceof took " + elapsed + " ns");
start = System.nanoTime();
for (int i = 0; i < reps; i++) {
for (Animal a : li) {
switch (a.type) {
case Animal.LION_TYPE:
((Lion) a).roar();
break;
case Animal.DEER_TYPE:
((Deer) a).runAway();
break;
}
}
}
elapsed = System.nanoTime() - start;
System.out.println("type constant took " + elapsed + " ns");
}
}
abstract class Animal {
public static final int LION_TYPE = 0;
public static final int DEER_TYPE = 1;
String name;
public final int type;
public Animal(String name, int type) {
this.name = name;
this.type = type;
}
public abstract void accept(AnimalVisitor av); // <-- Open up for visitors.
}
class Lion extends Animal {
public Lion(String name) {
super(name, LION_TYPE);
}
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, DEER_TYPE);
}
public void runAway() {
// System.out.println("Running...");
}
public void accept(AnimalVisitor av) {
av.visit(this); // <-- Accept and call visit.
}
}
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();
}
}
Test results:
Visitor took 920842192 ns
instanceof took 511837398 ns
type constant took 535296640 ns
This visitor pattern introduces 2 extra method calls that are unnecessary with instanceof. This is probably why it's slower.
Not that performance is the only consideration, but notice how 2 instanceofs are faster than even a 2-case switch statement. Plenty of people have worried about the performance of instanceof, but this should put the worry to rest.
As a Java Developer, I feel frustrated when people have a dogmatic attitude about avoiding the use of instanceof, because there have been several times in my work I wanted to clean up or write new clean code by using instanceof, but coworkers/superiors didn't approve of this approach , because they have more or less blindly accepted the idea that instanceof should never be used. I feel frustrated because this point is often driven home with toy examples that don't reflect real business concerns.
Whenever you pursue modular software design, there will always be times when type-dependent decisions need to be isolated from the types in question, so that the types have as few dependencies as possible.
This visitor pattern doesn't break modularity, but it's not a superior alternative to instanceof.
Upvotes: 2
Reputation: 39907
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();
}
}
}
Upvotes: 13
Reputation: 533870
The simplest approach is to have the super class implement a default behaviour.
public enum AnimalBehaviour {
Deer { public void runAway() { System.out.println("Running..."); } },
Lion { public void roar() { System.out.println("Roar"); } }
public void runAway() { }
public void roar() { }
}
public class Animal {
private final String name;
private final AnimalBehaviour behaviour;
public Animal(String name, AnimalBehaviour behaviour) {
this.name = name;
this.behaviour = behaviour;
}
public void runAway() { behaviour.runAway(); }
public void roar() { behaviour.roar(); }
}
public class TestAnimals {
public static void main(String... args) {
Animal[] animals = {
new Animal("Geo", AnimalBehaviour.Lion),
new Animal("Bambi", AnimalBehaviour.Deer),
new Animal("D2", AnimalBehaviour.Deer)
};
for (Animal a : animals) {
a.roar();
a.runAway();
}
}
}
Upvotes: 1
Reputation: 31
Pattern matching support in the language eliminates the need for the ugly visitor pattern.
See this Scala code for example:
abstract class Animal(name: String)
class Lion(name: String) extends Animal(name) {
def roar() {
println("Roar!")
}
}
class Deer(name: String) extends Animal(name) {
def runAway() {
println("Running!")
}
}
object TestAnimals {
def main(args: Array[String]) {
val animals = List(new Lion("Geo"), new Deer("D1"), new Deer("D2"))
for(animal <- animals) animal match {
case l: Lion => l.roar()
case d: Deer => d.runAway()
case _ => ()
}
}
}
Upvotes: 3
Reputation: 3894
Consider adding an interface for the action (Roar, Run away, etc) which is set on the animal in the constructor. Then have an abstract method such as act() on the Animal class which gets called similar to what Adeel has.
This will let you swap in actions to act out via a field at any time.
Upvotes: 1
Reputation: 93197
Here you have a List
of animals. Usually when you have a list of Objects, all these objects must be able to do the same thing without being casted.
So the best two solutions are :
abstract
in Animal
)Lion
from Deer
from the start, and have two different lists.Upvotes: 2
Reputation: 47403
If your method is not polymorphic you can't do without the cast. To make it polymorphic, declare a method in the base class and override it in the descendant classes.
Upvotes: 2
Reputation: 240966
Yes provide a method called action()
in abstract class , implement it in both of the child class, one will roar other will runaway
Upvotes: 5