Java classes and java error "cannot find symbol" - java

Can you explain me please. Why I get this error message?
I had typed this code:
public class Animal {
private int size = 0;
private int health = 5;
private int attackPoint = 2;
public int getAttackPoint() {
return attackPoint;
}
public class Cat extends Animal {
public void attackTarget (Animal target) {
target.setHealth(target.getHealth() - this.getAttackPoint());
}
}
class test {
public static void main(String[] args) {
Animal anfis = new Cat();
Animal barsik = new Cat();
anfis.setHealth(5);
barsik.setHealth(5);
barsik.attackTarget(anfis);
}
}
I thought link of class Animal can assigned value of Cat and It's OK.

You reference is Animal for create barsik and anfis object, but you not implement the attackTarget() method in this class. If you want use the attackTarget method from Cat class you should reference the barsik object to Cat:
Cat barsik = new Cat();
Or implement this method in Animal class:
public void attackTarget(Animal target) {
// Code Here
}
Also, the methods setHealth and getHealth is not defined in Animal class. For this:
public class Animal {
private int size = 0;
private int health = 5;
private int attackPoint = 2;
public int getAttackPoint() {
return attackPoint;
}
public void attackTarget(Animal target) {
// Code Here
}
public void setHealth(int healt) {
// Code Here
}
public int getHealth() {
return 0;
}
}
And:
public class Cat extends Animal{
public void attackTarget (Animal target) {
target.setHealth(target.getHealth() - this.getAttackPoint());
}
}
And:
public class test {
public static void main(String[] args) {
Animal anfis = new Cat();
Animal barsik = new Cat();
anfis.setHealth(5);
barsik.setHealth(5);
barsik.attackTarget(anfis);
}
}

There's a lot wrong with your code. You don't define all your functions, you define a class inside a class (which you can do but it is quite advanced and you probably don't want to do that). Take a look at the following which was done in Blue J:
public class Animal{
private int size = 0;
private int health = 5;
private int attackPoint = 2;
public int getAttackPoint() {
return attackPoint;
}
public void setHealth(int health){
this.health=health;
}
public int getHealth(){
return this.health;
}
}
public class Cat extends Animal {
public void attackTarget (Animal target) {
target.setHealth(target.getHealth() - this.getAttackPoint());
}
}
/* Notice that both anfis and barsik have access to the Animal methods but only barsik has access to the Cat methods.
*/
class test {
public static void main(String[] args) {
Animal anfis = new Cat();
Cat barsik = new Cat();
anfis.setHealth(5);
barsik.setHealth(7);
System.out.println(barsik.getHealth());
System.out.println(anfis.getHealth());
barsik.attackTarget(barsik);
System.out.println(barsik.getHealth());
}
}

Related

do i have to use instanof in this problem? or how should i code instead?

i wrote an example code for my question. i want to use polimorfism and i try to change a variable by the type of object. This code is working but is it the best way of that? Should i use a common method in both classes to return the variable? Thanks
package example;
import java.util.Scanner;
class Animal{}
class Dog extends Animal{}
class Bird extends Animal{}
public class Example {
public static void main(String[] args) {
Animal a;
int leg=0;
Scanner k=new Scanner(System.in);
String s=k.next();
if(s.equals("dog")) a=new Dog();
else a=new Bird();
if(a instanceof Dog) leg+=4;
else if(a instanceof Bird) leg+=2;
System.out.println(leg);
}
}
You should place common functionality into the parent class Animal and implement specific functionality into child classes Bird and Dog.
abstract class Animal {
abstract int legs();
}
class Bird extends Animal {
#Override
int legs() {
return 2;
}
}
class Dog extends Animal {
#Override
int legs() {
return 4;
}
}
There's no need for instanceof, just call the legs method of Animal and the implementing class will output the correct value.
public class Example {
public static void main(String[] args) {
Animal animal;
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
if(s.equals("dog")) {
animal = new Dog();
} else {
animal = new Bird();
}
System.out.println(animal.legs());
}
}
Put the common attributes and behaviors to the parent
abstract class Animal {
public abstract int getLegs();
}
class Bird extends Animal {
#Override
public int getLegs() {
return 2;
}
}
class Dog extends Animal {
#Override
public int getLegs() {
return 4;
}
}
, Add a method that creates an object based on parameter this is Factory Design pattern factory_pattern.htm
public static void main(String[] args) {
Animal animal;
Scanner scanner = new Scanner(System.in);
String animalType = scanner.next();
animal = getAnimal(animalType);
if (animal != null)
System.out.println(animal.getLegs());
scanner.close();
}
static Animal getAnimal(String type) {
if(type==null || "".equals(type)) return null;
Animal animal;
if ("dog".equalsIgnoreCase(type)) {
animal = new Dog();
} else if("bird".equalsIgnoreCase(type){
animal = new Bird();
}
return animal;
}
The number of legs the animal has should be contained within the subclass of Animal rather than set from the outside as you've currently got. Something like:
public abstract class Animal {
protected int numLegs;
public int getNumLegs() {
return numLegs;
}
}
public class Dog extends Animal {
public Dog() {
numLegs = 4;
}
}
Good luck!

In an ArrayList of Object, how can I convert Object into one of 3 instance of classes contained in an ArrayList?

I'm doing a simple Zoo application to understand oriented object concepts in Java.
My model is as follow:
1) A Zoo has a number of Cages
2) A Cage has a a mixture of Feline, Primate or Bird
3) An Animal can eat, sleep or drink
4) Feline extends Animal (Do extra Feline stuff)
5) Primate extends Animal (Do extra Primate stuff)
6) Bird extends Animal (Do extra Bird stuff)
The problem:
While it's pretty easy to handle x number of cages in a zoo (ArrayList of Cage), I'm struggling with the Animals in Cage.
I found out that I need to have an ArrayList of Object.
So far so good, but when I try to obtain my animal back and have him scratch a post, it's not a Feline anymore, it's an Object.
public class Cage{
private String name;
private ArrayList<Object> animals = new ArrayList<Object>();
public Cage(String name){
this.name = name;
}
public void addFeline(String name){
Feline newFeline= new Feline(name);
this.animals.add(newFeline);
}
public void addPrimate(String name){
Primate newPrimate= new Primate(name);
this.animals.add(newPrimate);
}
public void addBird(String name){
Bird newBird= new Bird(name);
this.animals.add(newBird);
}
public void removeAnimal(int index){
this.animals.remove(index);
}
public Object getAnimal(int index){
Object myAnimal = this.animals.get(index);
return myAnimal;
}
}
And the way I call it:
Zoo myZoo = new Zoo("My Zoo");
myZoo.addCage("Monkey Exhibit");
Cage myCage = myZoo.getCage(0);
myCage.addFeline("Leo");
Object MyAnimal = myCage.getAnimal(0);
The Question: How can I turn Object back into instance of class Feline so it can Scratch a Post?
I think the best way to approach this problem would be using the Strategy design pattern.
Feline, Primate and Bird should implement an interface Animal. The Cage would then have a method public void addAnimal(Animal animal);
The object creation for Feline, Primate and Bird should be outside of Cage.
I have put together some code if this can help. I would design the application similar to something below.
Behaviours should be encapsulated using interfaces. e.g. EatingBehaviour
public interface Animal {
public String getName();
}
public interface EatingBehaviour {
public void howManyTimes();
}
public class RealLionEatingBehaviour implements EatingBehaviour{
#Override
public void howManyTimes() {
System.out.println("I eat once a day");
}
}
public class ToyLionEatingBehaviour implements EatingBehaviour {
#Override
public void howManyTimes() {
System.out.println("I never eat! I am a toy lion.");
}
}
public abstract class Feline implements Animal{
public abstract void scratchPost();
private EatingBehaviour eatingBehaviour;
public EatingBehaviour getEatingBehaviour() {
return eatingBehaviour;
}
public void setEatingBehaviour(EatingBehaviour eatingBehaviour) {
this.eatingBehaviour = eatingBehaviour;
}
}
public class Lion extends Feline {
private String name;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
Lion (String name) {
this.name=name;
}
public void scratchPost(){
System.out.println(getName() + " Lion Scratching Post!");
}
}
public class AnimalFactory {
public static Animal getAnimalInstance(String type, String name){
Animal animal=null;
if ("lion".equalsIgnoreCase(type)) {
animal = new Lion(name);
}
return animal;
}
}
import java.util.ArrayList;
import java.util.List;
public class Cage {
private List<Animal> animals = new ArrayList<Animal>();
public void addAnimal(Animal animal) {
animals.add(animal);
}
public void removeAnimal(int index){
this.animals.remove(index);
}
public Animal getAnimal(int index){
return this.animals.get(index);
}
}
public class Zoo {
public static void main(String args[]) {
Cage cage = new Cage();
Animal animal = null;
animal = AnimalFactory.getAnimalInstance("Lion", "Sweety");
cage.addAnimal(animal);
Animal animalFromCage = cage.getAnimal(0);
if (animalFromCage instanceof Feline) {
Feline feline = (Feline) animalFromCage;
feline.setEatingBehaviour(new RealLionEatingBehaviour());
feline.scratchPost();
feline.getEatingBehaviour().howManyTimes();
feline.setEatingBehaviour(new ToyLionEatingBehaviour());
feline.getEatingBehaviour().howManyTimes();
}
}
}
Use a cast:
Object myAnimal = myCage.getAnimal(0);
Feline f = (Feline) myAnimal;
private List<Animal> animals = new ArrayList<Animal>();
public void findAnimal(int index) {
Animal myAnimal = animals.get(index);
if (myAnimal instanceof Feline) {
Feline feline = (Feline) myAnimal;
//do the work with Feline
} else if (myAnimal instanceof Primate) {
//do the work with Primate
}
// continue with the other types.
}
this will avoid a unexpected classcast exception. Since you know the type use the super type (Animal) in the Arraylist instead fo Object. if it is Obejct you can add anything to the List.
You should use an ArrayList<? extends Animal> instead of ArrayList<Object>. You would then cast a return value to the appropriate subclass of Animal.

How to protect class to be instantiated directly

How can I change this implementation:
public interface Animal()
{
public void eat();
}
public class Dog implements Animal
{
public void eat()
{}
}
public void main()
{
// Animal can be instantiated like this:
Animal dog = new Dog();
// But I dont want the user to create an instance like this, how can I prevent this declaration?
Dog anotherDog = new Dog();
}
Create a factory method and protect the constructor:
public class Dog implements Animal {
protected Dog () {
}
public static Animal createAsAnimal () {
new Dog ();
}
}
You can do it as follows by creating a factory method :
public interface Animal {
public void eat();
public class Factory {
public static Animal getAnimal() {
return new Dog();
}
private static class Dog implements Animal {
public void eat() {
System.out.println("eats");
}
}
}
}
The Dog class is not visible to the user.
To run :
Animal dog= Animal.Factory.getAnimal();
dog.eat();//eats

what will be OODesign for the following

I was asked to finish this test in one of my interview and they wanted me to create classes intereface following all the right practices. I couldn't clear the interview but I sure am interested how you all experts out there would handle this.
Create an OODesign for the following scenario
There is a zoo, its has some animals.
Following are the animals which live in the zoo
Lion
Tiger
Bear
Each animal has enerygy level
Every animal speaks, eats, play
by defalut when animal eat they gain +8 energy level
by default when animal play they loose -5 energy level
by defalut when animal speak they loose -1
By default each animal speak "Grrr..."
By default every animal when they play they say "I am loving it"
Only bear can dance but when bear dance he says "Look MA' I am dancing"
Following are the foods available for animals
Grain, Steak and salmon
When soundOff() method gets called on Zoo
every animal speak
When Tiger speaks it says "ROARR..."
When Lion speaks he says "Don't you dare ask me"
I would structure Zoo to contain a collection of the Animal base class to start with:
class Zoo {
private Collection<Animal> animals;
...
public void soundOff() {
Iterator<Animal> i = animals.iterator();
while( i.hasNext() )
i.next().speak();
}
then the Animal base class has the common methods/properties: speak, eat, play, energy level; also allow for the animal to reject food they don't like in the eat() method:
abstract class Animal {
private int energyLevel;
private String playMessage;
private String speakMessage;
...
public Animal(String speakMessage, String playMessage) {
this.speakMessage = speakMessage;
this.playMessage = playMessage;
}
public Animal() {
this( "Grrr...", "I am loving it" );
}
...
public abstract void eat( Food f ) throws IllegalArgumentException;
public void play() {
System.out.println( playMessage );
energyLevel += 8;
}
public void speak() {
System.out.println( speakMessage );
energyLevel -= 1;
}
..
}
then you can have specialized classes -- like DancerAnimal:
abstract class DancerAnimal extends Animal {
private String danceMessage;
public DancerAnimal(String speakMessage, String playMessage, String danceMessage) {
super( speakMessage, playMessage );
this.danceMessage = danceMessage;
}
public DancerAnimal( String danceMessage ) {
super();
this.danceMessage = danceMessage;
}
public void dance() {
System.out.println( danceMessage );
}
...
}
based on this you can implement Bear:
class Bear extends DanceAnimal {
public Bear() {
super( "Look MA' I am dancing" );
}
...
}
Lion and Tiger would just extend Animal base class and Food would probably be an enum.
My 2 cents on it.
Bear in mind that the above doesn't handle concurrency -- so one thread calling dance while the other calls play will corrupt the energyLevel -- but you can simply add a Lock around this.
class AnimalZoo {
public int energyLevel=0;
public String defaultVoice = "Grrr";
public String sing = "I am lovinig t";
public static void main(String [] args) {
Tiger t = new Tiger();
Lion l = new Lion();
Bear b = new Bear();
AnimalZoo az = new AnimalZoo();
az.soundOff();
}
public void soundOff() {
t.speak();
l.speak();
b.speak();
}
public void eat {
energyLevel+=8;
}
public void play{
energyLevel-=5;
}
public void speak {
energyLevel-=1;
}
}
}
class Lion extends AnimalZoo {
defaultVoice = "Don't you dare ask me";
System.out.printnln(defaultVoice);
}
class Tiger extends AnimalZoo {
public void speak {
defaultVoice = "ROARR";
System.out.println(defaultVoice);
}
}
class Bear extends AnimalZoo {
public void dance() {
System.out.println("Look MA' I am dancing");
}
Not all what you're looking for but something like this would help you to figure it out, d
eclare an animal class with all the properties and behavior common to all of them, then declare all the classes that define properties and behavior for each animal that extends the base class:
abstract class Animal
{
private int energyLevel;
public Animal(int eLevel)
{
setEnergyLevel(eLevel);
}
public void setEnergyLevel(int eLevel)
{
this.energyLevel = eLevel;
if(energyLevel <= 0)
{
energyLevel = 0;
}
}
public void speak()
{
System.out.println("grr...");
setEnergyLevel(energyLevel - 1);
}
public void eat()
{
setEnergyLevel(energyLevel + 8);
}
public void play()
{
System.out.println("I'm loving it...");
setEnergyLevel(energyLevel - 5);
}
}
class Lion extends Animal
{
public Lion(int energy)
{
super(energy);
}
}
class Bear extends Animal
{
public Bear(int energy)
{
super(energy);
}
public void dance()
{
System.out.println("I am dancing...");
}
}
class Tiger extends Animal
{
public Tiger(int energy)
{
super(energy);
}
}
Try the following code:
public abstract class Animal {
int energyLevel = ZooAnimalConstants.DEFAULT_ENERGY;
String speakMessage;
String playMessage;
public Animal(int energy) {
this.setEnergyLevel(energy);
speakMessage="Grr...";
playMessage="I am loving it";
}
public void setEnergyLevel(int energy) {
if (energy < 0) {
this.energyLevel = ZooAnimalConstants.DEFAULT_ENERGY;
} else {
this.energyLevel = energy;
}
}
public void speak() {
System.out.println("speak message : "+speakMessage);
this.setEnergyLevel(this.energyLevel - ZooAnimalConstants.MINUS_SPEAK_ENERGY);
}
public void eat() {
this.setEnergyLevel(this.energyLevel + ZooAnimalConstants.ADD_EAT_ENERGY);
}
public void play() {
System.out.println("play message : "+playMessage);
this.setEnergyLevel(this.energyLevel - ZooAnimalConstants.MINUS_PLAY_ENERGY);
}
public int getEnergyLevel()
{
return this.energyLevel;
}
}
Dance Behaviour:
public interface DanceBehaviour {
public abstract void dance();
}
public class Bear extends Animal implements DanceBehaviour{
public Bear() {
super(ZooAnimalConstants.BEAR_DEFAULT_ENERGY);
}
public void dance()
{
System.out.println("Look MA' I am dancing");
}
#Override
public String toString() {
// TODO Auto-generated method stub
return "Bear";
}
}
public class Tiger extends Animal {
public Tiger() {
super(ZooAnimalConstants.TIGER_DEFAULT_ENERGY);
super.speakMessage = "ROARR ..";
}
#Override
public String toString() {
// TODO Auto-generated method stub
return "Tiger";
}
}
public class Lion extends Animal {
public Lion() {
super(ZooAnimalConstants.LION_DEFAULT_ENERGY);
this.speakMessage = "Don't you dare ask me";
}
#Override
public String toString() {
// TODO Auto-generated method stub
return "Lion";
}
}
import java.util.ArrayList;
public class Zoo {
ArrayList<Animal> listAnimal;
public Zoo()
{
listAnimal= new ArrayList<Animal>();
}
public void addAnimal(Animal animal)
{
if(null != listAnimal && null != animal)
{
listAnimal.add(animal);
}
}
public void soundOff()
{
for(Animal animal : listAnimal)
{
animal.speak();
}
}
public void printAnimalEnergyReport()
{
for(Animal animal : listAnimal)
{
System.out.println("Energy Level for : "+animal.toString() + " : "+animal.energyLevel);
}
}
}
public interface ZooAnimalConstants {
int DEFAULT_ENERGY=0;
int ADD_EAT_ENERGY = 8;
int MINUS_SPEAK_ENERGY = 1;
int MINUS_PLAY_ENERGY = 5;
int TIGER_DEFAULT_ENERGY=5;
int LION_DEFAULT_ENERGY=6;
int BEAR_DEFAULT_ENERGY=4;
}
public class ZooDemoMain {
public static void main (String args[])
{
Zoo myZoo = new Zoo();
Animal tiger = new Tiger();
Animal bear = new Bear();
Animal lion = new Lion();
myZoo.addAnimal(tiger);
myZoo.addAnimal(lion);
myZoo.addAnimal(bear);
myZoo.soundOff();
myZoo.printAnimalEnergyReport();
bear.setEnergyLevel(0);
if(bear.getEnergyLevel() == 0)
{
bear.eat();
myZoo.printAnimalEnergyReport();
}
}
}

How to avoid large if-statements and instanceof

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 ?
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.
}
}
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();
}
}
}
Yes provide a method called action() in abstract class , implement it in both of the child class, one will roar other will runaway
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 _ => ()
}
}
}
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.
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 :
Having a common method for the two concrete classes (so defined as abstract in Animal)
Separate Lion from Deer from the start, and have two different lists.
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.
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.
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();
}
}
}

Categories

Resources