Java. Реализовать иерархию классов Животные

Реализовать иерархию классов Животные (Animals) и Еда (Food). Животные на делятся травоядных и те, которые едят только мясо. Еда делится соответственно(Для травоядных и для хищников). У животных должен быть метод, который определяет, сможет ли животное съесть заданную еду boolean eat() , а так же, созданный класс должен иметь конструктор для всех полей. Я никак не пойму, как можно это правильно реализовать. Для меня вся проблема в разделении животных на типы, и в дальнейшем использовании этих типов в методе. Буду очень благодарен за объяснение того, как это правильно сделать.


Ответы (2 шт):

Автор решения: Андрей Туманов

Не знаю как на Java, но на C# это будет выглядеть примерно так:

using System;
namespace Food
{
    abstract class Animal
{ 
    abstract public bool eat(Food _food);
    abstract public string name();
}
abstract class Food
{ 
    abstract public bool isMeat();
    abstract public string name();
}
class Predator : Animal
{ 
    override public bool eat(Food _food)
    { 
        return _food.isMeat();
    }
    override public string name()
    { 
        return "Хищник";
    }
}
class Herbivorous : Animal
{ 
    override public bool eat(Food _food)
    { 
        return !_food.isMeat();
    }
    override public string name()
    { 
        return "Травоядное";
    }
}
class Meat : Food
{ 
    override public bool isMeat()
    { 
        return true;
    }
    override public string name()
    { 
        return "Мясо";
    }
}
class Vegetable : Food
{ 
    override public bool isMeat()
    { 
        return false;
    }
    override public string name()
    { 
        return "Овощ";
    }
}

class Program
{
    static void Main(string[] args)
    {
        Animal a1 = new Predator();
        Animal a2 = new Herbivorous();
        Food food1 = new Meat();
        Food food2 = new Vegetable();
        check(a1, food1);
        check(a1, food2);
        check(a2, food1);
        check(a2, food2);
        Console.ReadLine();
    }
    static void check(Animal _animal, Food _food)
    {
        if (_animal.eat(_food))
        { 
            Console.WriteLine($"{_animal.name()} с удовольствем съест {_food.name()}");
        }
        else
        { 
            Console.WriteLine($"{_animal.name()} не будет есть {_food.name()}");
        }
    }
}

}

Результат:

Хищник с удовольствем съест Мясо

Хищник не будет есть Овощ

Травоядное не будет есть Мясо

Травоядное с удовольствем съест Овощ


Смысл:

Создаем абстрактный класс Животные, от него два потомка Хищники и Травоядные.

Создаем абстрактный класс Еда, от него два типа еды Мясо и Овощ

В главной программе создаем экземпляр нужного класса Хищника или Травоядное, записываем ссылку на этот экземпляр в переменную типа Животное.

Эта переменная не знает какое там животное, но из нее можно вызвать метод Ест? который вернет да или нет.

Также создаем нужные экземпляры еды Мясо или Овощ.

И пытаемся накормить Животное этой Едой.

Животное само скажет ест оно эту еду или нет.

Вспомогательный метод check просто выводит результат проверки.

→ Ссылка
Автор решения: Alexander Chernin

Есть такое предложение по архитектуре (да, лучше поздно, чем никогда):

import java.util.*;

interface Food {
}

// Базовый тип для чего-то мясного
interface Meat extends Food {
}

// Базовый тип для чего-то травяного
implements Grass extends Food {
}

// Для демонстрации что наследование работает как надо, 
// объявим "специфические" мясо и зелень
class Beef implements Meat {
}
class Carrot implements Grass {
}

// Базовый класс для животных
class Animal {
    // foodTypes - перечень типов еды, которую ест животное
    Animal(List<Class<?>> foodTypes) {
        this.foodTypes = new ArrayList(foodTypes);
    }
    
    boolean eat(Food food) {
        // Проверяем тип еды на "потребляемость"
        for(Class<?> _type: this.foodTypes) {
            if (_type.isInstance(food) ) {
                return true;
            }
        }
        return false;
    }

    // Травоядное
    boolean isHerbivore() {
        return this.eat(Glass.class);
    }

    // Плотоядное
    boolean isCarnivorous() {
        return this.eat(Meat.class);
    }

    // Список типов еды, которое данное животное может есть
    protected List<Class<?>> foodTypes = new ArrayList();
}

// Какой-то мясоед
class APredator extends Animal {
    APredator() {
        // Только мясная диета
        super(Arrays.asList(Meat.class));
    }
}

// Какой-то веган
class AVegan extends Animal {
    AVegan() {
        // Только трава, но не Weed, потому что это другое
        super(Arrays.asList(Grass.class));
    }
}

class Main {
    public static void main(String[] args) {
        APredator cat = new APredator();
        // Нормальная еда, true
        System.out.println(cat.eat(new Beef()));

        // Ешь сам, false
        System.out.println(cat.eat(new Carrot()));
    }
}

Метод Class.isInstance(object) служит для проверки того, что object создан из данного типа, или его наследников

→ Ссылка