views:

282

answers:

8

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 ?

+5  A: 

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

org.life.java
+2  A: 

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.

Petar Minchev
+8  A: 

Animal

public abstract class Animal {
 String name;

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

 public abstract void doWhatYouSupposeToDo();

}

Lion

public class Lion extends Animal {

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

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

Deer

public class Deer extends Animal {

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

 public void doWhatYouSupposeToDo() {
  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.doWhatYouSupposeToDo();    
  }

 }
}
Adeel Ansari
Also, this could easily be extended to use a strategy pattern. Supplying in the action to take place (with a separate setter, or in constructor) upon doWhatYouSupposeToDo(). Although it might be better to call it act() or perform()
Steven
@Steven: I tend to agree, with both of your suggestions. I just came up with this name arbitrarily. Yes, it sounds stupid and cute ;D.
Adeel Ansari
Proposed alternative method name: exhibitNaturalBehaviour()
mikera
+16  A: 

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 doWhatYouAreSupposeTo) 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.
    }
}
aioobe
Yes, tend to agree. I can't resist voting up visitor. I love it, but I think you do more than I do. +1
Adeel Ansari
@aioobe: Its regarding the description you added later, with visitor adding any new `Animal` will require modification of `AnimalVisitor`. Whereas, the other option is good to go without this kinda modification. What say you?
Adeel Ansari
@Adeel Ansari, That a good point. It depends on the situation I'd say. It depends on if you want the specific action-implementations to be collected in one class, or if you want them scattered in the different classes. Both are preferable in different situations. In this scenario however, `roar` and `runAway` are so different that I wouldn't want to invent a common name for the two.
aioobe
Wouldn't it be possible to do the implementation of the accept method in the parent class (Animal)?
Pau
No, unfortunately not. This is because the method signature is determined in compile time, while the target type is in this case determined at runtime.
aioobe
+2  A: 

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.
Colin Hebert
+1  A: 

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.

Steven
+2  A: 

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 _       => ()
    }
  }
}
Eric Grindt
I don't if it work's but it looks nice.
Emil
why is both the case's 'a' ?
Emil
@Emil: It works. It's tested. :)
Eric Grindt
Can you explain a bit how this works.i'm not into scala.
Emil
@Emil: 'a' is simply a label assigned to the object matched on that case.
Eric Grindt
@Emil: It's exactly equivalent to your Java way (`instanceof` and then cast). Pattern matching just makes it syntactically nicer. :)
Eric Grindt
ok i get it now thnx.
Emil
@Emil: Welcome. :)
Eric Grindt
+1  A: 

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(); 
     } 
   }
 }
Peter Lawrey
good approach.i like it.
Emil
The use of Enum in this case is not very flexible, as there will only exist a single Deer behaviour instance. (The Deer behaviour can thus not, for instance, have a reference to the related deer-object, as the behaviour is shared with other Deer instances.) Besides, it's not very elegant to be able to write myDeer.roar().
aioobe
@aioobe:yes your right.I didn't think much about that.
Emil
You should only need one Deer behviour as it is intended to describe all deers. If you need a more complicated structure you can't use enum alone. But I wouldn't start assuming a problem is more complicated than it needs to be. You should always strive for the simplest solution which meets your needs.
Peter Lawrey