Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it bad OOP practice to subclass MANY classes from a base class?

I'm relatively new to this site so if I am doing something wrong when it comes to posting questions and whatnot please let me know so I can fix it for next time.

I'm curious as to whether or not it is bad OOP practice to subclass multiple classes from a single base class. That probably doesn't quite make sense so I'm going to elaborate a little bit.

Say for instance you are designing a game and you have several different monsters you might come across. The approach I would take is to have a base abstract class for just a general monster object and then subclass all of the specific types of monsters from the base class using a new class.

One of my instructors told me that you shouldn't rely on inheritance in this case because the number of monsters will continue to grow and grow and the number of classes will increase to a point where it is hard to keep track of all of them and thus yo will have to recompile the program with every new class added in the future.

I don't understand why (or even if) that's a bad thing. If anybody could help me understand where my professor is coming from that would be much appreciated.

Thanks!

like image 722
user3390653 Avatar asked Sep 13 '25 01:09

user3390653


2 Answers

If monsters are very similar, in that the only differences are (for example) their name, how much damage they impart, what color they are, etc., then these differences which can be reflected in a field (in values), may make sub-classing unnecessary.

If, however, you have monsters that are fundamentally different from others, such that it is necessary to have very different methods and logic, and more specifically, differences that cannot be reflected in fields, then a sub-class SpecialMonster may be necessary.

But again, even SpecialMonster may not need to be sub-classed by individual monster types, as it's fields may be enough to distinguish between them.

While it's legal to have a million sub-classes of specific monster types, you don't want to take care of all that duplicate code when it could simply be expressed in the fields of new Monster instances, such as

new Monster("Goob", WakeTime.NOCTURNAL, 35, new Weapon[]{sword, hammer, knittingNeedle});
new Monster("Mister Mxyzptlk", WakeTime.ANYTIME, 71, new Weapon[]{sword, mindMeld, cardboardCutter});

There is an alternative, where you do have a lot of classes, but you don't impose them onto your users, and you don't clutter up your API/JavaDoc with them. If your Monster happens to be an abstract class

public abstract class Monster  {
   private final String name;
   ...
   public Monster(String name, int default_damage, WakeTime wake_time, Weapon[] weapons)  {
      this.name = name;
      ...
   }
   public String getName()  {
      return  name;
   }
   ...
   public abstract int getDamage(int hit_strength);
}

Then you could have a Monster convenience creator like this:

/**
  <P>Convenience functions for creating new monsters of a specific type.</P>
 **/
public class NewMonsterOfType  {
  private NewMonsterOfType()  {
     throw  new IllegalStateException("Do not instantiate.");
  }
  /**
     <P>Creates a new monster that is nocturnal, has 35-default-damage, and whose weapens are: sword, hammer, knittingNeedle.</P>
   **/
  public static final GOOB = new GoobMonster();
  /**
     <P>Creates a new monster that can be awake at any time, has 71-default-damage, and whose weapens are: sword, mindMeld, cardboardCutter.</P>
   **/
  public static final MISTER_MXYZPTLK = new MisterMxyzptlkMonster();
}
class GoobMonster extends Monster  {
  public GoobMonster()  {
     super("Goob", WakeTime.NOCTURNAL, 35, new Weapon[]{sword, hammer, knittingNeedle});
  }
   public int getDamage(int hit_strength)  {
     return  (hit_strength < 70) ? getDefaultDamage() : (getDefaultDamage() * 2);
  }
}
class MisterMxyzptlkMonster extends Monster  {
  public GoobMonster()  {
     super("Mister Mxyzptlk", WakeTime.ANYTIME, 71, new Weapon[]{sword, mindMeld, cardboardCutter});
  }
   public int getDamage(int hit_strength)  {
     return  (hit_strength < 160) ? getDefaultDamage() + 10 : (getDefaultDamage() * 3);
  }
}

In order for these private (actually package-protected) classes to not show up in you JavaDoc, you need to set its access to something either protected or public.

like image 129
aliteralmind Avatar answered Sep 15 '25 14:09

aliteralmind


Inheritance is quite natural in your scenario as all the specific monsters ARE base monsters as well :). I'd actually use inheritance a lot here, since probably specific monsters do have specific behaviour that would have to be overriden. MonsterA might move by crawling while MonsterB might move by flying. The base AMonster would have an abstract Move() method , implemented by those sub types.

This isn't a final answer, it really much depends on the game needs, however, in simplified form, inheritance makes sense here. The number of monster types might continue to grow, but really, are they all the same? The monster design is just based on grouping together some predefined data/behaviour? The game is quite trivial then...

I really get the impression your instructor doesn't code games for a living (me neither, although I did make a game some time ago), but his explanation why you shouldn't use inheritance is way too simplified. The number of defined classes is never an issue in an app, the more the better IF the Single Responsibility Principle is respected.

About you have to recompile your app.... yeah, when you fix a bug you have to recompile it too. IMO, the reasons he gave to you aren't valid for this scenario. He needs to come up with much better arguments.

In the mean time, go for inheritance.

like image 44
MikeSW Avatar answered Sep 15 '25 15:09

MikeSW