Pergunta

I try to implement a fluent interface in my 2D game engine.

Simplified example of my implementation:

public class Sprite<T> {

    protected float x = 0.0;
    protected float y = 0.0;

    public T setPosition(float x, float y) {
        this.x = x;
        this.y = y;
        return (T)this;
    }

}

public class Living<T extends Living> extends Sprite<Living> {

    protected boolean alive = false;

    public T setAlive(boolean alive) {
        this.alive = alive;
        return (T)this;
    }

}

public class Entity<T extends Entity> extends Living<Entity> {

    protected String name = null;

    public T setName(String name) {
        this.name = name;
        return (T)this;
    }

}


Entity entity = new Entity().setPosition(100, 200).setAlive(true).setName("Zombie");

I keep getting the error: "The function setAlive(boolean) does not exist."

I know, using my methods the other way round (in a more logical order) works:

Entity entity = new Entity().setName("Zombie").setAlive(true).setPosition(100, 200);

And I know that overwriting any parent setter functions in each and every child class would work:

public class Entity extends Living {

    protected String name = null;

    public Entity setPosition(float x, float y) {
        return (Entity)super.setPosition(x, y);
    }

    public Entity setAlive(boolean alive) {
        return (Entity)super.setAlive(alive);
    }

    public Entity setName(String name) {
        return (Entity)super.setName(name);
    }

}

But I want the interface to be as free/uncomplicated as possible for the 'end user' and the code to be as compact and clean as it gets.

I don't know if I just messed up the generics or my hole approach is completely wrong. I hope you can help. I am open to any advice. (Sorry for my bad english.)

Edit: I already tested the following approach and it works for the Entity class.

public class Sprite<T> {
...
}

public class Living<T> extends Sprite<T> {
...
}

public class Entity extends Living<Entity> {
...
}

I forgot to mention, that I need to instantiate Sprite & Living too. For example:

Living living = new Living().setPosition(50, 50).setAlive(false);
Foi útil?

Solução 2

I think your class model is over complicated, you can pass generic parameter down to the child class and then declare it explicitly:

public class Sprite<T> {
...
}

public class Living<T> extends Sprite<T> {
...
}

public class Entity extends Living<Entity> {
...
}

Outras dicas

This is a valiant attempt at the curiously recurring template pattern in Java. The problem is that you're mixing generics and raw types which means you aren't "closing the loop" of the pattern. For example your declaration of Living:

public class Living<T extends Living> extends Sprite<Living>

Should really be:

public class Living<T extends Living<T>> extends Sprite<T>

At some point you'll need to declare a "leaf" class that resolves T, otherwise you won't be able to instantiate and declare variables of these types without resorting to raw types or wildcards (which defeats the purpose of the pattern). For example:

public final class ConcreteEntity extends Entity<ConcreteEntity>

See my answer here for more details on implementing this pattern.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top