13

I am designing my own little OOP program to simulate Vampires, Wolves, Humans and Trucks and am trying to implement my own limited understanding of Interfaces.

(I am still abstracting here and have no code implementation yet, so it's rather a question of OOP design...I think!)

Am I right in looking for 'common behaviour' between these classes and implementing them as interfaces?

For example, Vampires and Wolves bite...so should I have a bite interface?

public class Vampire : Villain, IBite, IMove, IAttack

Likewise for Trucks...

public class Truck : Vehicle, IMove

And for Humans...

public class Man : Human, IMove, IDead

Is my thinking right here? (Appreciate your help)

  • 14
    Animals, vegetables and minerals seldom make good examples for application implementations. Actual implementations are generally more abstract, like IEnumerable, IEquatable, etc. – Robert Harvey Sep 29 '16 at 18:05
  • 6
    You have one single mention of what your objects are about to do in your software ("bite"). Software is normally designed to do something, basing an object model on characteristics only is not leading anywhere. – tofro Sep 30 '16 at 8:27
  • @tofro My intention was that IBite would contain multiple methods that would implement behavior regarding (1) The reducing of another's 'life/energy' level (2) The appearance or invocation of 'blood' graphics and (3) the updating of simulation statics data (such as NoOfBites). I think i can appreciate that an interface is best used to implement a range of method behaviors. – user3396486 Sep 30 '16 at 10:11
  • 2
    Do not classes Human, Vampire and Vehicle implement the IMove interface already? Why do you need to make the subclasses implement it too explicitely? – Pierre Arlaud Sep 30 '16 at 11:45
  • Are all this interfaces really necessary? In Python luckily you don't need any of this stuff, ehich was a really refreshing change (my first language was Object Pascal). Also virtual methods might be a better solution in some cases. – Ajasja Sep 30 '16 at 12:07
33

In general you want to have interfaces for common characteristics of your clasess.

I semi-agree with @Robert Harvey in the comments, who said that usually interfaces represent more abstract features of classes. Nevertheless, I find starting from more concrete examples a good way of starting to think abstract.

While your example is technically correct (i.e. yes, both vampires and wolves bite, so you can have an interface for that), there is a question of relevance. Each object has thousands of characteristics (e.g. animals may have fur, can swim, can climb trees, and so on). Will you make an interface for all of them? Very less likely.

You usually want interfaces for things that make sense to be grouped in an application as a whole. For example, if you are building a game, you can have an array of IMove objects and update their position. If you don't want to do that, having the IMove interface is pretty useless.

The point is, don't over engineer. You need to think about how are you going to use that interface, and 2 classes having a method in common is not a good enough reason to create an interface.

  • 1
    I certainly hope each object does not have thousands of attributes. – gardenhead Sep 29 '16 at 18:32
  • 4
    Attributes not as in oop attributes but grammar attributes/characteristics (things such as enumerable, comparable, etc) :D. Bad choice of words. – Paul92 Sep 29 '16 at 18:44
  • 3
    Worth noting that the interfaces that are useful are the ones you'll use. For example, IBite isn't particularly useful, but you might want IAttack so you can work over all the things that make attacks, or an IUpdate so you can run the updates for everything, or an IPhysicsEnabled so you can apply physics to them, etc. – anaximander Sep 30 '16 at 8:42
  • 1
    This answer raises some very good points. Final paragraph sums it up pretty well; at least as well as you can with the level of detail provided. – Lightness Races with Monica Sep 30 '16 at 10:39
  • 1
    grouping commons methods fits more for abstract classes. Interface are made to design contracts that must respect those who implements it, not grouping same implementation for some objects. – Walfrat Sep 30 '16 at 14:25
28

Looks like you're creating a bunch of single method interfaces. This is fine on the face of it but keep in mind that interfaces are not owned by the class/es that implement them. They are owned by the clients that use them. The clients decide if something needs to be something that can move and attack.

If I have a Combat class with a fight() method, that method likely has a need to call both move() and attack() on the same object. That strongly suggests a need for an ICombatant interface that fight() can call move() and attack() through. This is cleaner than fight() taking an IAttack object and casting it to IMove to see if it can also move.

That doesn't mean you can't also have IMove IAttack interfaces. I just hope you aren't making them without some client needing them. Conversely, if no client ever needs to make an object both move and attack then ICombatant isn't needed.

This simple way of looking at interfaces is often lost because people like following examples. The first interfaces we're exposed to are in libraries. Unfortunately, libraries have no idea what their clients are. So they can only guess at their clients needs. Not the best example to follow.

  • 1
    Damn this is good. Gaming just seems like a really good way to use and explain OOP. – JeffO Sep 29 '16 at 20:46
  • 6
    @JeffO until you actually implement a reasonably large game and realize that OOP is a hot mess and you would be better off with component-based systems or data-oriented designs. – Darkhogg Sep 30 '16 at 6:45
  • "Interfaces are owned by the clients that use them" – Tibos Sep 30 '16 at 10:09
  • 4
  • 1
    +1 for the difference between libraries and application, I often (too much ? :/) read tons of things that just fit for one and not the other. – Walfrat Sep 30 '16 at 14:28
3

Consider whether it will be common to have collections of objects with different combinations of abilities, and whether code might want to perform an action upon those items, within a collection, that support it. If so, and if there would be a sensible "default behavior" for objects which don't have useful support for some action, it may be helpful to have interfaces implemented by a wide range of classes, not just those that can behave usefully.

For example, suppose only a few kinds of creature can have Woozles, and one wants such creatures to have a NumerOfWoozles property. If such a property were in an interface that were only implemented by creatures that can have Woozles, then code which wanted to find the total number of Woozles held by a collection of creatures of mixed types would have to say something like:

int total = 0;
foreach (object it in creatures)
{
   IWoozleCountable w = trycast(it, IWoozleCountable);
   if (w != null) total += w.WoozleCount;
}

If, however, WoozleCount were a member of Creature/ICreature, even though few subtypes would override Creature's default WoozleCount implementation that always returns zero, the code could be simplified to:

int total = 0;
foreach (ICreature it in creatures)
   total += it.WoozleCount;

While some people might chafe at the idea of having every Creature implement a WoozleCount property that's really only useful for a few subtypes, the property would be meaningful for all types, whether or not it would be useful with items known to be of those types, and I would regard the "kitchen sink" interface as being less of a code smell than the trycast operator.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.