0

I've run into a design problem in my java code. My application uses missiles, and there are different types of missiles that all work identical except they have 3 unique attributes. The constructor of a missile must know these attributes. I decided to make missile an abstract class, but I can't assign values to protected variables in a subclass outside of a method/constructor. Also I can't declare the variables in the constructor, because I must make the call to the super-constructor first thing. How can I be smart about this problem?

public abstract class Missile {

private int x, y;
private Image image;
boolean visible;

private final int BOARD_WIDTH = 390;

protected final int MISSILE_SPEED;
protected final int MISSILE_HEIGHT;
protected String file;

public Missile(int x, int y) {
    ImageIcon ii =
        new ImageIcon(this.getClass().getResource(file));
    image = ii.getImage();
    visible = true;
    this.x = x;
    this.y = y - Math.floor(MISSILE_HEIGHT/2);
}


public Image getImage() {
    return image;
}

public int getX() {
    return x;
}

public int getY() {
    return y;
}

public boolean isVisible() {
    return visible;
}

public void move() {
    x += MISSILE_SPEED;
    if (x > BOARD_WIDTH)
        visible = false;
}
}

And there is an ideal implementation of a subclass, except it doesn't work. (it can't recognize the protected variables). What do I do?

public class Laser extends Missile {

    MISSILE_SPEED = 2;
    MISSILE_HEIGHT = 5;
    file = "laser.jpg";

public Laser(int x, int y) {
    super(x, y);
}

}

user2651804
  • 1,464
  • 4
  • 22
  • 45
  • @trevor-e No, the compiler still requests an identifier for them – user2651804 Nov 01 '13 at 17:36
  • why dont you parameterize the constructor of the Missile class to accept the MISSILE_SPEED/MISSILE_HEIGHT as well. These could be passed from the subclasses but need not be exposed from subclass constructors – Dev Blanked Nov 01 '13 at 17:38
  • @DevBlanked Since I only have like 2 different missiles, this would eliminate the need for Missile to be abstract at all. I just don't think it's a very good solution to give Missile 4 int parameters. I was looking for a way to specifically avoid that. – user2651804 Nov 01 '13 at 17:41

4 Answers4

4

I think the best way to do what you want it to do is make abstract methods in Missile that the subclasses have to implement. For example, add these to Missile:

public abstract int getMissileSpeed();
public abstract int getMissileHeight();
public abstract int getFileName();

Then your subclass has to implement it, and you can make it constant like so:

public class Laser extends Missile {

    public Laser(int x, int y) {
        super(x, y);
    }

    public int getMissileSpeed() {
        return 2;
    }

    public int getMissileHeight() {
        return 5;
    }

    public String getFileName() {
        return "laser.jpg";
    }

}

edit: And then of course anywhere that you want to retrieve the constant value you just call those methods.

telkins
  • 10,440
  • 8
  • 52
  • 79
  • Yes, I was experimenting with that thought. I'd hoped it wouldn't come to that. Any reason you don't have an abstract method for file attribute? (since different missiles have different animations) – user2651804 Nov 01 '13 at 17:44
  • @user2651804 Sorry forgot to add that in! I actually like this solution because you can easily scale in as many properties as you need. To do so you just add to the base abstract Missile class and then your IDE should help you easily add them to all subclasses. – telkins Nov 01 '13 at 17:46
3

Change the base class fields and constructors to

protected final int speed;
protected final int height;

public Missile(int x, int y, int speed, int height, String file) {
    ImageIcon ii =
        new ImageIcon(this.getClass().getResource(file));
    image = ii.getImage();
    visible = true;
    this.speed = speed;
    this.height = height;
    this.x = x;
    this.y = y - Math.floor(height/2);
}

And the subclass to:

public class Laser extends Missile {
    public Laser(int x, int y) {
        super(x, y, 2, 5, "laser.jpg");
    }

    ...
}

The attributes are already in the base class, so they must not be redefined in the subclass. All-uppercase naming is reserved to constants in Java.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • This is a good quick solution if the OP doesn't plan on adding more fields later on imo. Otherwise the number of constructor arguments will grow quite a bit and you will need to refactor to a Builder pattern to manage it. – telkins Nov 01 '13 at 17:43
  • Yes, or to wrap several fields into an object (like a Point for x and y. But it's much better than to call an overridable method from the constructor of the base class, like the accepted answer does. This is a bad practice, because the subclass fields won't be initialized yet when the method is called by the base class constructor. – JB Nizet Nov 01 '13 at 18:55
1

I'm not sure if missile needs to be an abstract class, but I think something like this might be what you're going for:

public abstract class Missile {

    private int x, y;
    private Image image;
    boolean visible;

    private final int BOARD_WIDTH = 390;

    protected final int MISSILE_SPEED;
    protected final int MISSILE_HEIGHT;

    public Missile(int x, int y, int speed, int height, String file) {
        MISSILE_SPEED = speed;
        MISSILE_HEIGHT = height;

        ImageIcon ii = new ImageIcon(this.getClass().getResource(file));
        image = ii.getImage();
        visible = true;
        this.x = x;
        this.y = y - Math.floor(MISSILE_HEIGHT/2);
    }

}

public class Laser extends Missile {

    public Laser(int x, int y) {
        super(x, y, 2, 5, "laser.jpg");
    }

}
Darius Makaitis
  • 880
  • 1
  • 5
  • 5
0

Create an interface and put all your final fields in it. Now implement this interface within Missile and Laser both. At least that would solve the issue of access.

Ashish
  • 1,121
  • 2
  • 15
  • 25
  • 1
    This could be a solution I might like a lot. It's just not a very detailed answer - can u elaborate how this would work? – user2651804 Nov 01 '13 at 17:56