3

I have two classes, LivingCreature ,and Animal which inherits from it.

I want to implement a class for each existing Animal, but since different animals share lots of features, I want to be able to classify Animals into several categories: Flying, Walking, Swimming, Carnivore, Vegeterian and so on...

Every animal can reside in several, even from the same area, for example Flying, Walking and Carnivore.

Also, each category may hold several unique attributes, for example a flying animal should consist speed and eating type (e.g. whether it sits on a tree picking worms, or "raiding" the earth and picking animals with its legs)

The First thing that I definitely want to avoid is to hold a different set of fields for each concrete animal implementation.

Now, since some categories are simply binary (Carnivore or Vegan) and some are definitely not, I wonder what would be the right way to implement it.

I tend to go towards interfaces for each category, even if they won't be holding any methods , but I'm encountering a conflict:

  • It looks odd to hold an interface for such simple use like isMeatEating which holds a single boolean field.
  • On the other hand, having several categories as Animal's fields and several others implemented as Interfaces, sound very wrong and confusing.

What would be the correct/best option here, design-wise? (Perhaps there's a design pattern which matches this use-case)

Eliran Abdoo
  • 611
  • 6
  • 17
  • As OOP point of view, you would use abstract class, but with Java refusing diamond relation, you will need to do some choice to defined the most logic inherited structure and add the rest use a relation probably. In Java 8, you can add default implementation in interface, not perfect but can do the trick for some case (carefull to that usage too) – AxelH May 23 '17 at 09:56
  • 2
    You may want to check this [Composition over inheritance](http://en.wikipedia.org/wiki/Composition_over_inheritance) – Ythio Csi May 23 '17 at 09:57
  • 1
    If they have no methods and you just need to see if they *have it*, just use an attribute. – Turtle May 23 '17 at 09:58
  • @YthioCsi It looks as if the subject matches my question, but the problem is that by using this paradigm, Animal class will have tons of fields (since I need fields instead of methods), and hence each inheriting class will hold all of these fields, which brings me back to the most naive implementation. Perhaps a better idea would be to have the Animal class almost naked, and creating an inheriting class for each possible category, and then using multiple inheritance ? – Eliran Abdoo May 23 '17 at 10:13
  • First let's organize info by grouping related categories like Flying, Walking, Swimming together in a group and Carnivore, Vegetarian into another group. Since every group can hold only specific correct set of values this means they are actually Enums. So we will have `MovementType` Enum and `FoodType` Enum. Therefore you can use these enums simply for properties in Animal class. – M.Sameer May 23 '17 at 10:17
  • @M.Sameer As I mentioned, a concrete class can have several movment types, so I can't group the set of categories to several enums such that every concrete class doesn't have two attribute from the same enum. – Eliran Abdoo May 23 '17 at 10:28
  • The properties do not have to be simple. If there are more than one value for the movement type you will need a `Set` property. I also want to ask if you have Cat, Dog, Eagle classes that inherit from Animal, will you need to instantiate those classes ? Will you have for example fluffy that's an instance of Cat and lucky an instance of a Dog? If the answer is No then Cat, Dog, .. etc are actually instances of Animal with different property values. – M.Sameer May 23 '17 at 10:37
  • It's not clear for what reason you create method `isMeatEating`. You could test if an animal is `Vegetarian` by instanceof: `Animal bird = new Eagle(); if (bird instanceof Vegetarian`) {//do something}`. In that case Vegetarian is most likely interface (possibly without any method) since it's orthogonal to Flying/Walking – ADS May 24 '17 at 12:38
  • I would have taken the base `Animal` functionality and then extended into `FlyingAnimal`, `RunningAnimal`, etc. Then maybe I would have done something like `class Tiger implements RunningAnimal, Carnivore {...}` – Jay May 24 '17 at 17:53
  • Categories in OOP should not be defined using types (interface inheritance). The reason being is that Categories are not static notion, they can change based on set of object field values and operations. For example if you need a JumpingSwimming category, are you going to have it implemented by most of you swimming animals? Most like you wont. You will simply derive it by checking if Animal object can swim and jump. So just dont have interfaces for categories but interfaces that define Animal's capabilities and then simply derive your category by inpecting those capabilities. – tsolakp May 25 '17 at 20:11

1 Answers1

0

The pattern that you seem to describe is that of a trait or perhaps a mixin.

Mixins are a language concept that allows a programmer to inject some code into a class. Mixin programming is a style of software development, in which units of functionality are created in a class and then mixed in with other classes.

Some languages, like Scala, have built-in support for these concepts.

In Java 8, with the help of default methods, we can do traits to some extend, and I say so, because that is not the reason why default methods were designed.

Now, it is hard to suggest ideas on your design without having full details of what you're doing, but I'll try to give an example of how I see it from my perspective.

Let's focus on eating profiles: carnivores vs herbivores. Carnivores eat other animals, herbivores eat plants or things of vegetal origin and omnivores may eat both. Both animals and plants are edible materials.

interface Edible {
   Collection<Nutrients> getNutrients();
}

interface Vegetal extends Edible {}
interface Animal extends Edible{}

All animals eat, so we could define animal as:

interface Animal<T extends Edible> extends Edible {

    Stomach getStomach();
    Collection<Bolus> masticate(T food);

    default void eat(T food) {
        Objects.requiresNonNull(food, "The food must not be null");
        for(Bolus bolus : this.masticate(food)) {
            this.getStomach().ingest(bolus);
        }
    }
}

Spare me the details of Stomach and Bolus, and let's just assume all animals have a stomach and a way to masticate the food, turn it into a bolus and ingest it into their stomachs.

Now, we can finally reach our definition of:

interface Carnivore extends Animal<Animal> { }
interface Herbivore extends Animal<Vegetal> { }
interface Omnivore extends Animal<Edible> { }

Now you can define a

class Chicken implements Herbivore {}
class Lion implements Carnivore {}
class Bear implements Omnivore {}

Now a Chicken can only eat things of Vegetal type, and Lion only things of Animal type, whereas Bear can eat any Edible thing.

The more details I put on the default methods of my interface Animal, the less details I will need to implement in these classes and tha'ts, perhaps, a way to accomplish what you want.

I am aware that I may have not been able to answer your question, but I hope I have at least given you some ideas of where you can continue your investigation and experimentation of the ideal solution.

Edwin Dalorzo
  • 76,803
  • 25
  • 144
  • 205