OEurix
OEurix

Reputation: 433

List<Super Class> which contains objects of different subclasses

Now I have a class Animal, with three subclasses extending it: Dog, Cat, and Fish.

class Dog extends Animal {
    public void bark(){}
}
class Cat extends Animal {
    public void catchMouse(){}
}
class Fish extends Animal {
    public void swim(){}
}

And I have a list:

List<Animal> listOfAnimals = new ArrayList<>();

Then I use a static method to add objects of Dog, Cat and Fish to the list:

public static void addAnimal(List<Animal> list, AnimalInfo info) {
    Animal animal = new Animal();
    switch (info) {
        case 0:
            animal = new Dog();
            break;
        case 1:
            animal = new Cat();
            break;
        case 2:
            animal = new Fish();
            break;
    }
    list.add(animal);
}

I call this static method 3 times and add a Dog object, a Cat object and a Fish object to the list in order. Now the list should contain a Dog instance, a Cat instance and a Fish instance.

Now I want to call bark() on the Dog instance:

list.get(0).bark();

But this will not work obviously.

What is the best way to achieve this? Use:

(Dog)(list.get(0)).bark();

Upvotes: 2

Views: 2186

Answers (3)

Nate
Nate

Reputation: 67

Another way of doing this is through interface

    interface IAnimal {
    public void Roar();
    public void Swim();
}

class Animal implements IAnimal{

    @Override
    public void Roar() {
        // TODO Auto-generated method stub
        System.out.println("IROAR");
    }

    @Override
    public void Swim() {
        // TODO Auto-generated method stub
        if (!(this instanceof Lion)) {

            System.out.println("ISWIM");
        }
        else {
            System.out.println("this animal cannot swim");
        }
    }
}

Notice that I added a check for Lion instance for Swim() method since not all animals can swim.

Client Code:

    List<IAnimal> animals = new ArrayList<>();
    animals.add(new Lion());
    animals.add(new Dog());
    animals.get(0).Swim();
    animals.get(1).Roar();

Upvotes: 0

Alex Hart
Alex Hart

Reputation: 1703

I think utilizing inheritance here could be a good approach in this case, but I thought I'd share an alternative.

Another approach here is to use the visitor pattern. This is especially good when you don't know what you need to do with an object when you declare its class, or if you have contextual behaviour (such as updating another object's state) that you want to keep separate from your Animal classes (Separation of Concerns)

abstract class Animal {
    abstract void accept(AnimalVisitor visitor);
}
class Dog extends Animal {
    void bark() { ... }

    @Override
    void accept(AnimalVisitor visitor) {
        visitor.visit(this);
    }
}
class Cat extends Animal {
    void meow() { ... }

    @Override
    void accept(AnimalVisitor visitor) {
        visitor.visit(this);
    }
}

interface AnimalVisitor {
    void visit(Dog dog);
    void visit(Cat cat);
}

// Somewhere else...

AnimalVisitor voiceVisitor = new AnimalVisitor() {
    @Override
    void visit(Dog dog) {
        dog.bark();
    }

    @Override
    void visit(Cat cat) {
        cat.meow();
    }
}

animalList.get(0).accept(voiceVisitor);

Upvotes: 3

user8426627
user8426627

Reputation: 943

What is the best way to achieve this?

If you use List of Animals you should use Animal-only methods further in program logick. The idea of List is that you iterating over it any apply the same to items. Make:

 class Animal {
      public void voice(){}
      public void swim(){}
    }

class Dog extends Animal {
    public void voice(){
          print('bark')}

}
class Cat extends Animal {
    public void voice(){
          print('meow')}
}

And if you do want to have a list of all animals, they just do noting, instead of calling is instance of what is more expencive

Upvotes: 1

Related Questions