Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Abstract Base Class or Class?

For my semester project, my team and I are supposed to make a .jar file (library, not runnable) that contains a game development framework and demonstrate the concepts of OOP. Its supposed to be a FRAMEWORK and another team is supposed to use our framework and vice-versa. So I want to know how we should start. We thought of several approaches:
1. Start with a plain class

public class Enemy {
    public Enemy(int x, int y, int health, int attack, ...) {
        ...
    }
    ...
}
public class UserDefinedClass extends Enemy {
    ...
}

2. Start with an abstract class that user-defined enemies have to inherit abstract members

public abstract class Enemy {
    public Enemy(int x, int y, int health, int attack, ...) {
        ...
    }
    public abstract void draw();
    public abstract void destroy();
    ...
}
public class UserDefinedClass extends Enemy {
    ...
    public void draw() {
        ...
    }
    public void destroy() {
        ...
    }
}

3. Create a super ABC (Abstract Base Class) that ALL inherit from

public abstract class VectorEntity {
    ...
}
public abstract class Enemy extends VectorEntity {
    ...
}
public class Player extends VectorEntity {
    ...
}
public class UserDefinedClass extends Enemy {
    ...
}

Which should I use? Or is there a better way?

like image 830
Mohit Deshpande Avatar asked May 13 '10 23:05

Mohit Deshpande


2 Answers

Well, it's a bit hard to say for sure without knowing in depth what you're doing, and even then it's rather subjective. However, there are some things to consider which could tell you.

  1. Are they going to actually instantiate an Enemy, or do all enemies really need to be of a derived type? If you're not actually going to be instantiating Enemies rather than derived types, then it should likely be either an interface or an abstract class.

  2. If you're looking to provide actual behavior in your base class, then obviously it needs to be a class rather than an interface.

  3. Methods which need to be there for the API but don't make any sense for you to be providing any implementations for should be abstract.

  4. Methods where it makes good sense to have implementations for them in the base class should have implementations in the base class. And if it doesn't make good sense for them to be overridden, then make them final.

  5. Making classes share a common base class really only makes sense if they're really sharing behavior or you need to be able to treat them all the same somewhere in your code. If they're not really all that similar, then they probably shouldn't share a base class. For instance, if both Enemy and Player are supposed to be displayable, it may make sense to have a common base class which handles their display functionality. But if Enemy were something that was displayable, and Player was a more abstract concept - like the controller of the game - and wasn't displayable, then it probably wouldn't make sense for them to share a base class. In general, it's better to prefer composition rather than inheritance when building classes, so if the classes in question aren't really going to be sharing behavior and don't really have an "is-a" relationship with a common base class, then they shouldn't share a common base class.

  6. Prefer to have your base classes only share methods, not data. In other words, in an inheritance tree, it's best that only the leaves be instantiable. There are various things like equals() which break down when you have base classes with actual data in them. That's not to say that you can't do that - people do it all the time - but it can cause problems and is best avoided if it isn't needed.

  7. Prefer to override abstract methods. Otherwise, in derived classes, you risk not calling the base class' method or totally changing what the method does.

I'm sure that I could come up with more, but without really being familiar with your project, it's bound to be rather generic. Out of the 3 options that you gave, I'd probably go with 2. 3 seems like you'd probably be creating a base class for unrelated classes, and 1 would result in Enemy being instantiatable, which you probably don't need and would definitely make it so that more than the leaves in your inheritance hierarchy would be instantiatable. You'll probably still end up with data in base classes with 2, but you're more likely to only be overriding abstract methods, and you'll have fewer problems with altered behavior in derived classes.

like image 73
Jonathan M Davis Avatar answered Oct 20 '22 05:10

Jonathan M Davis


A fourth option would be to use interfaces.

interface Enemy {

    public void draw();

    . . .

}

If you're just starting out, I would avoid your third option. Let the framework develop a little and see if there's a need for it.

like image 1
Jeremy Kendall Avatar answered Oct 20 '22 06:10

Jeremy Kendall