Search code examples
javagenericsbounded-types

Generic type bounded by another generic


Suppose I have this:

interface Shape {}
interface Square extends Shape {}
interface Circle extends Shape {}

interface ShapeBuilder<S extends Shape> {}

I want something like this:

class ShapeBuilderFactory<SB extends ShapeBuilder> {
    SB<Square> getSquareBuilder(){...}
    SB<Circle> getCircleBuilder(){...}
}

This code doesn't compile (because ShapeBuilder is a raw type), but I hope you understand the idea. Is it possible to do something like this in java? How?

(the real problem isn't with shapes builders and factories, I used this example for simplicity)

Edit (more context)

I have different kind of builders:

interface RegularShapeBuilder<S extends Shape> extends ShapeBuilder<S> {}
interface FunnyShapeBuilder<S extends Shape> extends ShapeBuilder<S> {}

class RegularSquareBuilder extends RegularShapeBuilder<Square> {}
class FunnySquareBuilder extends FunnyShapeBuilder<Square> {}
class RegularCircleBuilder extends RegularShapeBuilder<Circle> {}
class FunnyCircleBuilder extends FunnyShapeBuilder<Circle> {}

And I want the factory to do things like this:

ShapeBuilderFactory<FunnyShapeBuilder> funnyShapeBuilderFactory = ...;
FunnyShapeBuilder<Square> funnySquareBuilder = funnyShapeBuilderFactory.getSquareBuilder();

Solution

  • I'm not sure why you wouldn't just have:

    class ShapeBuilderFactory {
        ShapeBuilder<Square> getSquareBuilder(){...}
        ShapeBuilder<Circle> getCircleBuilder(){...}
    }
    

    Edit

    So if you really must have the ShapeBuilder subtype in your factory, you'll need to declare each one of them:

    class ShapeBuilderFactory<SqB extends ShapeBuilder<Square>, 
                              CiB extends ShapeBuilder<Circle>> {
        SqB getSquareBuilder(){...}
        CiB getCircleBuilder(){...}
    }
    

    So you'll have to declare that as:

    ShapeBuilderFactory<FunnySquareBuilder, FunnyCircleBuilder> funnyShapeBuilder = ...
    

    But you will be able to say

    FunnyShapeBuilder<Square> funnySquareBuilder = funnyShapeBuilderFactory.getSquareBuilder();
    

    The problem you've got is that an implementation of ShapeBuilder can only create one type of shape. That's how you've declared it.

    If this were my code I would use the ShapeBuilderFactory definition I initially wrote and instantiate it with funny or regular builders. Isn't the point of having these interfaces actually using them?