1

Example, let's say from a game:

public class Enemy {
    protected int x, y;
    protected int width, height;
    protected int hitpoints;
    protected int speed;
}

I want to have multiple classes extending this one (one for every enemy type) but I need to make sure (preferably force this) somehow that the extending class assigns values to all of these variables.

I don't want to pass them through a constructor call or set them in it - so currently I'm forced to do this by simply copying the entire decelerations into every class and assigning them values in the same line.

Is there perhaps a more efficient way to do this? (Sorry if the question is somewhat vague..)

Thanks in advance.

Edit - This is how I would create an extending class:

public class Skeleton extends Enemy {
    protected int x, y;
    protected int width, height;
    protected int hitpoints;
    protected int speed;
}
Sri Sankaran
  • 8,120
  • 4
  • 38
  • 47
Acidic
  • 6,154
  • 12
  • 46
  • 80
  • 6
    Sets all the variables **when**, if not at construction time? – Oliver Charlesworth Nov 16 '11 at 00:52
  • Can you post an example of what you're doing now, with an explanation of what's wrong with it? – Ted Hopp Nov 16 '11 at 00:53
  • I indeed want to set them at construction time, my question revolves around the manner with which I should assign multiple vital variables at an extending class. – Acidic Nov 16 '11 at 00:53
  • 2
    @Acidic: Then why not as superclass constructor parameters? – Oliver Charlesworth Nov 16 '11 at 00:54
  • Why not use a constructor? I hope you want to extend from your enemy class because you want polymorphic behaviour, and not only reuse code. – helpermethod Nov 16 '11 at 00:56
  • @OliCharlesworth because passing half a dozen or more, nameless numbers through the constructor doesn't seem very readable to me. – Acidic Nov 16 '11 at 00:58
  • At some point in time you are going to have to do that. If a skeleton for example will always have the same hitpoints etc, you can put it into the constructor without passing anything, so `public Skeleton(x,y){x=x;y=y;width=10;height=10;hitpoints=100;speed=5;}` Sorry about the lazy formatting, but hopefully you get the idea. – dann.dev Nov 16 '11 at 01:02
  • @dann.dev in terms of readability, to me it seems like a slightly worse version of what I'm doing at the moment. (This is what I used to do before) – Acidic Nov 16 '11 at 01:08
  • I don't know of any other way to do it sorry – dann.dev Nov 16 '11 at 01:18
  • You still end up ultimately with 4 numbers, but you could have Enemy take a Rectangle in the constructor, and use it to set x,y,width and height. And maybe hitpoints and speed could be grouped into some other Object. Might "look nicer". – user949300 Nov 16 '11 at 01:39
  • Having written a few RPG-style games I'd strongly recommend using a prototype pattern rather than inheritance for a game object hierarchy - they work a *lot* better once the hierarchy gets more complicated. The advantage then is that you just put all the "default" values you want in the prototype. – mikera Nov 16 '11 at 01:40

5 Answers5

4

One alternative to Jordão's answer would be to use the builder pattern:

public class SkeletonBuilder
{
    private int x, y, width, height...;        
    public SkeletonBuilder withCoords(int x, int y) { this.x = x; this.y = y; }
    public SkeletonBuilder withSize(int width, int height) { this.width = width; this.height = height; }
    ...

    public Skeleton build() { return new Skeleton(x, y, width, height); }
}

public class Skeleton
{
    /* package */ Skeleton(int x, int y, int width, int height, ...)
}

// game code

Skeleton skeleton = new SkeletonBuilder().withCoords(1, 4).withSize(2, 30).build();

If some of the params could be defaulted then set them up in the SkeletonBuilder constructor. If the other params are required, then you could either set a boolean flag in the builder, or use boxed objects, and fail in the build() method if they're not set.

SimonC
  • 6,590
  • 1
  • 23
  • 40
  • I like the concept. To insure that the caller has actually _assigned_ all the values, you'd have to initialize them to something "invalid" (like Integer.MIN_VALUE), and then SkeletonBuilder.build() would verify that they have all changed. – user949300 Nov 16 '11 at 19:06
1

To both force the subclasses to set the values in the constructor and to make the constructor call readable, you're going to have to write a lot more code in the superclass. This is one way I could think about it (just showing x and y):

abstract class Enemy {
  protected int x, y;

  protected Enemy(X x, Y y) {
    this.x = x.value;
    this.y = y.value;
  }

  protected static class X {
    private final int value;
    private X(int value) { this.value = value; }
  }
  protected static class Y {
    private final int value;
    private Y(int value) { this.value = value; }
  }
  protected static X x(int value) { return new X(value); }
  protected static Y y(int value) { return new Y(value); }
}

class Skeleton extends Enemy {
  public Skeleton() {
    super(x(12), y(13));
  }
}

UPDATE: if it makes sense to have composite types that encapsulate related values, they can make the code better:

class Skeleton extends Enemy {
  public Skeleton() {
    super(position(12, 13), size(300, 300), ...);
  }
}
Jordão
  • 55,340
  • 13
  • 112
  • 144
  • Do you know if the extra method calls that wrap it have any impact on performance? Or would it be to small to matter? Its a way of making it readable though. – dann.dev Nov 16 '11 at 01:24
  • I think it would be negligible. – Jordão Nov 16 '11 at 01:30
  • 1
    I don't see how this helps. You are still passing two numbers (12 & 13) up to Enemy. Easier to just call super(12,13). BUT... if you passed up a Point and a Dimension, or a Rectangle, that would cut down on some of the clutter. – user949300 Nov 16 '11 at 01:38
  • I'm just showing x and y, _imagine_ more arguments. Of course, if it makes sense to have types like what you described, that's definitely a good idea! – Jordão Nov 16 '11 at 01:57
  • Wow, this seems like an interesting option. I'll experiment with it. – Acidic Nov 17 '11 at 19:20
0

Your class Skeleton should not declare the same variables as set in Enemy.

As to your question, the simplest option is to make the variables final, and then set them in a constructor. The compiler will enforce that they are all set.

user949300
  • 15,364
  • 7
  • 35
  • 66
  • I know that I don't HAVE to do that, I simply hide the members of the extending class. As to setting them in the constructor... A line of code like this doesn't look very pleasing to me: `super(50,100,60,20,30,4);` – Acidic Nov 16 '11 at 01:06
  • I haven't done it recently, but you know you don't HAVE to call super? The fields that you inherit become part of the Skeleton so you can assign them in your skeleton constructor without passing them to the super. I'm not sure what best practices are. – dann.dev Nov 16 '11 at 01:13
  • A (worse, IMO) alternative would be to set all the values to a "strange" number (like -1 or Integer.MIN_VALUE), and then, at some "appropriate" time before using the object check that all the values have been changed. If not, throw an Exception. But determining the "appropriate" time may be tricky, and forcing the check is also difficult. I guess you could do so by requiring getters and checking then. – user949300 Nov 16 '11 at 01:17
  • 2
    Yet another option would be to change Skeleton to not extend Enemy, but to include it as a field. Composition instead of Inheritance. – user949300 Nov 16 '11 at 01:20
0

I think you should create a Type interface

interface Type
{
    int getX();
    int getY();
    int getWidth() ;
    int getHeight();
    int getHitpoints();
    int getSpeed();
}

Then the compiler will do the enforcement work.

emory
  • 10,725
  • 2
  • 30
  • 58
-1

Based on the comments (and although I would go with a constructor on the superclass) one way to go at it would be to declare the Enemy class as abstract (which probably should be if you just want to define common behaviour there) and initialize the variables as calls to abstract methods. This way the extending classes would be forced to implement those methods and in essence initialize the variables.

Here's a simplified example:

public abstract class Enemy {
    protected int x = getX();
    protected int y = getY();

    protected abstract int getX();
    protected abstract int getY();
}

public class Skeleton extends Enemy {
    @Override
    protected int getX() { return 10; }

    @Override
    protected int getY() { return 10; }
}

Its more verbose, but perhaps it achieves the readability you are looking for.

Francisco Paulo
  • 6,284
  • 26
  • 25
  • Sorry, I have to vote this down as complex. Also, getX() is a poor name - should be getInitialX() or some such. 99.9% of all programmer would expect getX() to return x. – user949300 Nov 16 '11 at 01:23
  • Good point, getInitialX() would indeed be a better name for the method. As for the complexity, i guess it just derives from the question itself... as I said, I would go with a simple constructor on the superclass with all the necessary fields. – Francisco Paulo Nov 16 '11 at 01:29
  • This only works if the values of X and Y are available at the time the object is constructed. – John Haager Nov 16 '11 at 01:39
  • Also, I think that Josh Bloch Effective Java strongly discourages calling any overloaded method in a constructor because bad things can happen. – user949300 Nov 16 '11 at 01:42