Search code examples
javaoop

How can I make a ball behave like a bouncing and elastic ball?


I have two classes BouncingBall and another one called ElasticBall. Both classes extends BallImpl which implements an interface called Ball.

public interface Ball {
    int DEFAULT_RADIUS = 50;
    
    int radius();
    Point center();
    void update();
}

public class BouncingBall extends BallImpl {
    public static final int MOVEMENT_SPEED = 12;
    
    static final int DOWN = 1;
    static final int UP = -1;
    
    private int direction;
    
    BouncingBall(int x, int y, int direction) {
        super(x, y);
        this.direction = direction;
    }
    
    @Override
    public void update() {
        direction = reverseDirectionIfNecessary();
        y = move();
    }
    
    private int reverseDirectionIfNecessary() {
        if (movingTooHigh() || movingTooLow()) {
            return switchDirection();
        }
    
        return this.direction;
    }
    
    private boolean movingTooLow() {
        return y + radius >= BallWorld.BOX_HEIGHT && movingDown();
    }
    
    private boolean movingTooHigh() {
        return y - radius <= 0 && movingUp();
    }
    
    private int switchDirection() {
        return movingDown() ? UP : DOWN;
    }
    
    private int move() {
        return y + (MOVEMENT_SPEED * direction);
    }
    
    private boolean movingDown() {
        return direction == DOWN;
    }
    
    private boolean movingUp() {
        return direction == UP;
    }
}

public class ElasticBall extends BallImpl {
    public static final int GROWTH_RATE = 2;
    
    static final int GROW = 1;
    static final int SHRINK = -1;
    
    private int growthDirection;
    
    ElasticBall(int x, int y, int radius, int growthDirection) {
        super(x, y, radius);
        this.growthDirection = growthDirection;
    }
    
    @Override
    public void update() {
        growthDirection = reverseGrowthDirectionIfNecessary();
        radius = next();
    }
    
    private int reverseGrowthDirectionIfNecessary() {
        if (growingTooBig() || shrinkingTooSmall()) {
            return switchDirection();
        }
    
        return this.growthDirection;
    }
    
    private boolean shrinkingTooSmall() {
        return radius <= 0 && shrinking();
    }
    
    private boolean growingTooBig() {
        return radius >= Ball.DEFAULT_RADIUS && growing();
    }
    
    private int switchDirection() {
        return growing() ? SHRINK : GROW;
    }
    
    private int next() {
        return radius + (GROWTH_RATE * growthDirection);
    }
    
    private boolean shrinking() {
        return growthDirection == SHRINK;
    }
    
    private boolean growing() {
        return growthDirection == GROW;
    }
}

I need to create a BouncingElasticBall which combines the behavior of the BouncingBall and the ElasticBall classes. I have poor knowledge in OOP, and I know that Java does not allow multiple inheritance, so how can I solve this problem?


Solution

  • One way you could approach this is to not extend BallImpl, but make sort-of plugins. Like this:

    public class BallImpl implements Ball {
        List<BallBehavior> behaviors = ...
    
        @Override
        public void update() {
           behaviors.forEach(behavior -> behavior.update(this));
        }
        ...
    }
    
    public interface BallBehavior {
        void update(BallImpl ballImpl);
    }
    

    And then, just write your elastic and bouncing logic as behaviors.