-2

I have a situation

public class Animal
{
   String noise;

  public String makeNoise()
  {
      return noise;
  }
}

Then there will be a subclass with the concrete definition of the noise.

public class Dog extends Animal{
   String noise = "woof";
}

also

public class Cat extends Animal{
   String noise = "meow";
}

What I want to do is

 Animal cat = new Cat();
 cat.makeNoise();  // This will be 'meow'

and

Animal dog = new Dog();
dog.makeNoise();  // This will be 'woof'

Basically, I don't want to repeat the makeNoise() method when I create an animal. However, this will not work. (Noise is an empty string)

I could use a static object like

static String NoiseDog = "woof"
static String NoiseCat = "meow"

but then again I have to write the makeNoise() method for each animal. Is there a better way to architect this?

user2689782
  • 747
  • 14
  • 31
  • 2
    Set the noise member of the super class in the constructor on each of the sub classes. You only need to implement makeNoise() in the super. – bhspencer Jul 07 '16 at 19:29

4 Answers4

2

If you want to force all sub-classes of Animal to have a noise defined, you can enforce that in the constructor:

public abstract class Animal {
    private final String noise;

    public Animal(final String noise) {
        this.noise = noise;
    }

    public String makeNoise() {
        return noise;
    }
}

Then Dog:

public class Dog extends Animal {
    public Dog() {
        super("woof");
    }
}

And Cat:

public class Cat extends Animal {
    public Cat() {
        super("meow");
    }
}

And to test it out:

public class Test {
    public static void main(String[] args) {
        final Animal dog = new Dog();
        System.out.println(dog.makeNoise());
        final Animal cat = new Cat();
        System.out.println(cat.makeNoise());
    }
}

Output:

woof
meow
Dan W
  • 5,718
  • 4
  • 33
  • 44
  • Thanks for this. In my real world example, there are 5 different parameters which need to be set differently for each class. So not really easy to pass 5 values in the constructor. – user2689782 Jul 07 '16 at 20:00
  • @user2689782 If you have 5 parameters to pass to `Animal`, you could wrap those parameters into another class `AnimalCharacteristics` and pass that to `Animal`. – Dan W Jul 07 '16 at 20:04
1
public class Cat extends Animal{
   String noise = "meow";
}

This creates an instance variable named "noise" that hides the superclass variable. Instead, you need this to set the superclass value:

public class Cat extends Animal{
   public Cat() {
      noise = "meow";
   }
}
FredK
  • 4,094
  • 1
  • 9
  • 11
0

Make the Animal class abstract. This way, there can be no such thing as an Animal object which calls makeNoise.

Then, set the noise String to a value within the constructor of each subclass as appropriate to that animal's sound.

Zircon
  • 4,677
  • 15
  • 32
0

Alternatively, you could implement an interface like so:

Animal:

public interface Animal {
    public String makeNoise();
}

Dog:

public class Dog implements Animal {
    public String makeNoise() {
        return "woof";
    }
}

Cat:

public class Cat implements Animal {
    public String makeNoise() {
        return "meow";
    }
}

Test:

public class Test {
    public static void main(String[] args) {
        Animal dog = new Dog();
        System.out.println(dog.makeNoise());
        Animal cat = new Cat();
        System.out.println(cat.makeNoise());
    }
}

Output:

woof
meow
Maxim Bravo
  • 75
  • 2
  • 11