views:

131

answers:

4

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?

A: 

My rule of conduct is that a long as there are more than one class that share the same operations/data/methods/functionality, they should be extensions of the same abstract class.

So, if it was me doing it:

  • If ALL classes have something in common, have an top-level abstract class that gathers this functionality/fields/data in one place.
  • If they don't, only those classes that actually have something in common should extend a lower-level abstract class.

If only methods are what the classes will have in common, interfaces can be used as well. However, I always find that sooner or later I see that the classes that implement the interface have the same private fields. At this point, I transform the interface to an abstract class that holds these private fields (to save on lines of code if nothing else).

Lars Andren
+1  A: 

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.

Jeremy Kendall
+3  A: 

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.

Jonathan M Davis
A: 

Just a small answer out of the book "More effective c++" page 271:

"Make base classes abstract that are not at the end of a hierachy". I'm too lazy to give you the whole chapert, but the autor lists some good reasons for that.

InsertNickHere
There's also "Effective Java," which is more applicable in this case. It says something similar but with things more specific to Java - like how `equals()` doesn't work quite right when mixing derived types and base types if the base classes aren't all abstract.
Jonathan M Davis