Animal Inheritance System with Advanced Features
Question
Design an object-oriented system in Java that implements an animal hierarchy with the following requirements:
1. Create an abstract class Animal
with:
- Abstract method makeSound()
- Abstract method move()
- Concrete method getAge()
- Protected field for age
2. Create interfaces Pet
and Wild
with appropriate methods
3. Implement Dog
, Cat
, and Bird
classes that extend Animal
4. Create Puppy
and Kitten
classes that extend Dog
and Cat
respectively
5. Use a Zoo
class to manage animals using a Map<String, Animal>
6. Implement a Visitor
pattern for animal interactions
7. Add support for animal training and tricks
8. Include proper exception handling and validation
Answer
Here's a implementation of the animal inheritance system:
Core Classes
-
Animal Abstract Class
public abstract class Animal { protected int age; protected String name; protected List<String> tricks; public Animal(String name, int age) { if (age < 0) { throw new IllegalArgumentException("Age cannot be negative"); } if (name == null || name.trim().isEmpty()) { throw new IllegalArgumentException("Name cannot be null or empty"); } this.name = name; this.age = age; this.tricks = new ArrayList<>(); } public abstract String makeSound(); public abstract void move(); public int getAge() { return age; } public String getName() { return name; } public void addTrick(String trick) { if (trick == null || trick.trim().isEmpty()) { throw new IllegalArgumentException("Trick cannot be null or empty"); } tricks.add(trick); } public List<String> getTricks() { return new ArrayList<>(tricks); } public void accept(AnimalVisitor visitor) { visitor.visit(this); } }
-
Interfaces
public interface Pet { void play(); void feed(); void groom(); } public interface Wild { void hunt(); void defend(); void markTerritory(); }
-
Animal Classes
public class Dog extends Animal implements Pet { private String breed; public Dog(String name, int age, String breed) { super(name, age); this.breed = breed; } @Override public String makeSound() { return "Woof!"; } @Override public void move() { System.out.println(name + " runs on four legs"); } @Override public void play() { System.out.println(name + " plays fetch"); } @Override public void feed() { System.out.println(name + " eats dog food"); } @Override public void groom() { System.out.println(name + " gets brushed"); } public void fetch() { System.out.println(name + " fetches the ball"); } } public class Cat extends Animal implements Pet { private boolean isIndoor; public Cat(String name, int age, boolean isIndoor) { super(name, age); this.isIndoor = isIndoor; } @Override public String makeSound() { return "Meow!"; } @Override public void move() { System.out.println(name + " walks gracefully"); } @Override public void play() { System.out.println(name + " plays with yarn"); } @Override public void feed() { System.out.println(name + " eats cat food"); } @Override public void groom() { System.out.println(name + " grooms itself"); } public void climb() { System.out.println(name + " climbs the tree"); } } public class Bird extends Animal implements Wild { private String species; private boolean canFly; public Bird(String name, int age, String species, boolean canFly) { super(name, age); this.species = species; this.canFly = canFly; } @Override public String makeSound() { return "Tweet!"; } @Override public void move() { if (canFly) { System.out.println(name + " flies through the air"); } else { System.out.println(name + " hops on the ground"); } } @Override public void hunt() { System.out.println(name + " hunts for insects"); } @Override public void defend() { System.out.println(name + " defends its nest"); } @Override public void markTerritory() { System.out.println(name + " sings to mark territory"); } public void buildNest() { System.out.println(name + " builds a nest"); } }
-
Subclasses
public class Puppy extends Dog { private boolean isHouseTrained; public Puppy(String name, int age, String breed, boolean isHouseTrained) { super(name, age, breed); this.isHouseTrained = isHouseTrained; } @Override public String makeSound() { return "Yip!"; } @Override public void move() { System.out.println(name + " runs and stumbles"); } public void learnTrick(String trick) { addTrick(trick); System.out.println(name + " learned to " + trick); } } public class Kitten extends Cat { private boolean isLitterTrained; public Kitten(String name, int age, boolean isIndoor, boolean isLitterTrained) { super(name, age, isIndoor); this.isLitterTrained = isLitterTrained; } @Override public String makeSound() { return "Mew!"; } @Override public void move() { System.out.println(name + " runs and pounces"); } public void learnTrick(String trick) { addTrick(trick); System.out.println(name + " learned to " + trick); } }
Zoo Management
- Zoo Class
public class Zoo { private final Map<String, Animal> animals; public Zoo() { this.animals = new HashMap<>(); } public void addAnimal(Animal animal) { if (animal == null) { throw new IllegalArgumentException("Animal cannot be null"); } if (animals.containsKey(animal.getName())) { throw new IllegalStateException("Animal with name " + animal.getName() + " already exists"); } animals.put(animal.getName(), animal); } public Animal getAnimal(String name) { return animals.get(name); } public void removeAnimal(String name) { animals.remove(name); } public void makeAllAnimalsSound() { animals.values().forEach(animal -> System.out.println(animal.getName() + ": " + animal.makeSound())); } public void trainAnimal(String name, String trick) { Animal animal = getAnimal(name); if (animal == null) { throw new IllegalArgumentException("Animal not found: " + name); } animal.addTrick(trick); } public List<Animal> getAnimalsByType(Class<? extends Animal> type) { return animals.values().stream() .filter(type::isInstance) .collect(Collectors.toList()); } }
Visitor Pattern
- Animal Visitor
public interface AnimalVisitor { void visit(Dog dog); void visit(Cat cat); void visit(Bird bird); void visit(Puppy puppy); void visit(Kitten kitten); } public class FeedingVisitor implements AnimalVisitor { @Override public void visit(Dog dog) { dog.feed(); } @Override public void visit(Cat cat) { cat.feed(); } @Override public void visit(Bird bird) { System.out.println(bird.getName() + " eats seeds"); } @Override public void visit(Puppy puppy) { puppy.feed(); } @Override public void visit(Kitten kitten) { kitten.feed(); } } public class TrainingVisitor implements AnimalVisitor { @Override public void visit(Dog dog) { dog.fetch(); } @Override public void visit(Cat cat) { cat.climb(); } @Override public void visit(Bird bird) { bird.buildNest(); } @Override public void visit(Puppy puppy) { puppy.learnTrick("sit"); } @Override public void visit(Kitten kitten) { kitten.learnTrick("come"); } }
Testing
- Zoo Tests
@Test public void testZooOperations() { Zoo zoo = new Zoo(); // Add animals Dog dog = new Dog("Rex", 3, "German Shepherd"); Cat cat = new Cat("Whiskers", 2, true); Bird bird = new Bird("Tweety", 1, "Canary", true); Puppy puppy = new Puppy("Max", 1, "Labrador", false); Kitten kitten = new Kitten("Luna", 1, true, true); zoo.addAnimal(dog); zoo.addAnimal(cat); zoo.addAnimal(bird); zoo.addAnimal(puppy); zoo.addAnimal(kitten); // Test animal sounds assertEquals("Woof!", zoo.getAnimal("Rex").makeSound()); assertEquals("Meow!", zoo.getAnimal("Whiskers").makeSound()); assertEquals("Tweet!", zoo.getAnimal("Tweety").makeSound()); // Test training zoo.trainAnimal("Max", "sit"); assertTrue(zoo.getAnimal("Max").getTricks().contains("sit")); // Test visitor pattern AnimalVisitor feedingVisitor = new FeedingVisitor(); zoo.getAnimal("Rex").accept(feedingVisitor); }
Usage Example
```java public class Main { public static void main(String[] args) { Zoo zoo = new Zoo();
// Create animals
Dog dog = new Dog("Rex", 3, "German Shepherd");
Cat cat = new Cat("Whiskers", 2, true);
Bird bird = new Bird("Tweety", 1, "Canary", true);
Puppy puppy = new Puppy("Max", 1, "Labrador", false);
Kitten kitten = new Kitten("Luna", 1, true, true);
// Add to zoo
zoo.addAnimal(dog);
zoo.addAnimal(cat);
zoo.addAnimal(bird);
zoo.addAnimal(puppy);
zoo.addAnimal(kitten);
// Make all animals sound
zoo.makeAllAnimalsSound();
// Train animals
zoo.trainAnimal("Max", "sit");
zoo.trainAnimal("Luna", "come");
// Use visitor pattern
AnimalVisitor feedingVisitor = new FeedingVisitor();
AnimalVisitor trainingVisitor = new TrainingVisitor();
for (Animal animal : zoo.getAnimalsByType(Animal.class)) {
animal.accept(feedingVisitor);
animal.accept(trainingVisitor);
}
}
}