2

I'm in a bit of a quandary. I have class animal, let's say it stores basic things like position, etc.. So then I have a class smartAnimal that extends animal. Let's say smartAnimal adds some functionality of being able to make decisions without the user's input.

Now, I have a class dog that extends animal. It doesn't extend smartAnimal because it doesn't need that functionality. So far I'm good: a dog is an animal and a smartAnimal is an animal. But now I want smartDog that would extend smartAnimal but smartDog should also be a dog. For example, a lot of the functionality in regular dog, let's say .sniff(), .poop(), and .bark() should also be in my smartDog but it won't be unless I literally copy+paste the code, because Java doesn't allow multiple inheritance.

Composition seems inelegant because if I had:

class smartDog{ smartAnimal thisSmartAnimal; dog thisDog; }

...I'd be duplicating the "stuff" in animal, like, for example, the position. I would have to deal with two sets of position variables! And duplicates of whatever properties there are in animal.

Inheriting multiple interfaces doesn't sound like the proper solution either, because let's say dog was an interface, .sniff(), .poop(), and .bark()'s implementation shouldn't have to vary and be re-implemented for smartDog and whatever other classes.

What's the best practice here? That is, to have both classes dog and smartDog?

EDIT:

From some of the comments/answers, let me clarify. In my specific project, a smartAnimal actually has a whole neural network that controls it. It's a lot of code, and doesn't make sense to abstract it to an interface. The core of the NN functionality is the same no matter what animal has it, but each smartAnimal subclass would implement the outputs of the AI "brain" differently. Conversely, each animal has it's own functionality that operates the same whether a human controls it or its own AI agent controls it.

honkbert
  • 135
  • 1
  • 7
  • 1
    `smartDog` should extend `dog` – Marek Sebera Feb 24 '13 at 23:44
  • But then I'd still be in the same situation, although vice versa, of having to copy+paste the `smartAnimal` functionality into `smartDog`... – honkbert Feb 24 '13 at 23:49
  • 1
    Oh I got the point now, it's hard in Java SE, more simple while using for example Scala or IoC pattern. – Marek Sebera Feb 24 '13 at 23:54
  • 1
    This isn't the traditional Java way, and wouldn't be necessary if your domain model is literally what you've described here (but I'm assuming your example isn't what you're actually trying to code), but if you truly need to be able to add/remove multiple roles to/from a single object, you could check out http://qi4j.org/ – Matt Browne Feb 24 '13 at 23:59
  • 1
    Copying is probably never suggested/recommended. This usually implies the need to refactor the idea to the right abstraction. In this case, I would think along the lines of what the objects "are" in this model and what they "do" separately. Dogs are probably considered "smart" if they can do tricks whereas dumb Dogs that don't implement the "Trick" interface are not. A Dog may be considered "smarter" than another Dog if it implements "Tricks", "Commands" and the "Obident" behaviors (interfaces). This is all relative. One could give weight to implemented Tricks and above a limit means "smart". – Darrell Teague Feb 25 '13 at 00:13
  • `Smart` should be an implementation of an interface. – Mr. Polywhirl Feb 25 '13 at 02:10

3 Answers3

3

The answer is that this isn't a realistic inheritance hierarchy, which you can tell from the fact that you used the words "adds some functionality" to describe adding methods in a subclass. This isn't proper inheritance. In proper inheritance (in Java, at least) every method should exist at the top level of the inheritance hierarchy. Inheritance is for code reuse, not for adding functionality as you go deeper into the tree. Therefore, there's not really an answer to your question as given.

Ryan Stewart
  • 126,015
  • 21
  • 180
  • 199
  • It's a question how you do work with your objects, and whether you're programming against interfaces. I don't see any reason why should every method exist at the to level of hierarchy only. – Marek Sebera Feb 24 '13 at 23:58
  • Yes, but I've seen the "an orange is a fruit but a fruit isn't (necessarily) an orange" example many times when it comes to inheritance. If `orange` extends `fruit`, because `orange` has some specific information/functionality to being an `orange`, that's not proper inheritance? – honkbert Feb 25 '13 at 00:02
  • Ryan is right and I would recommend this question be closed as it is not a question so much as a discussion topic and probably too broad for this kind of Q&A forum. – Darrell Teague Feb 25 '13 at 00:16
2

I think that what you may be looking for there is the new JDK 8 feature called "Default Implementation"

I Think the wise solution without that would be to have the dog inheriting smartAnimal. As such : A smartDog is a dog which is a smartAnimal which is an Animal.

It is difficult to have more precise advice as it really depends of what your objects are implementing. (Do they all have internal state for example ? or are they only defining new behaviours ?)

Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268
benzonico
  • 10,635
  • 5
  • 42
  • 50
2

Since we are talking about Java here, the model is single-inheritance with multiple interfaces.

That being said, given these examples, the right level of abstraction is appropriate. That is, the answer lies in a combination of:

  1. Proper inheritance (see GOF books on "is a", "has a" and behaviors). If you find yourself saying "a dog is smart" - that is probably a behavior of a dog versus "a dog is a mamal" (notice the noun versus adjective). A "smart" dog exhibits certain behaviors that are different from dumb dogs but both are "dogs" from a data-modeling point of view.
  2. Proper aggregation. Many times I find it useful to break complex "things" into their component parts. So a "car" is made up of an engine, transmission, chassis, etc. Dogs have fur (which have color, texture, etc), legs, heads, body-shapes, etc and it may be appropriate to differentiate that way when separating WHAT the dog IS versus HOW it BEHAVES (smart = interface).
  3. Abstract interfaces. What might be challenging in this example is that what "smart" is may vary between different types of objects/nouns. A "smart" dog might be able to understand commands whereas a "smart" phone has certain features like email. So "smart" may not be the appropriate interface at the highest level but might be associated with "mammals" -> "dog" being a mammal might implement the Mammal.Smart interface (being specific to Mammals).

This is indeed one of the more difficult and important aspects of information modeling and computer science as a whole. Entire groups of books and studies are devoted to this one topic and thus may not be appropriate as a Stack Overflow question, meant to provide straight-forward, simple answers to straight-forward concise questions.

Darrell Teague
  • 4,132
  • 1
  • 26
  • 38