Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic Type From Enum & The Builder Pattern

I'm trying to create a builder pattern that uses generics to provide type checking on some of the methods. Currently I have the following working:

ParameterBuilder.start(String.class).setName("foo").setDefaultValue("Hello").build();
ParameterBuilder.start(Integer.class).setName(bar).setDefaultValue(42).build();
ParameterBuilder.start(Boolean.class).setName(bar).setDefaultValue(false).build();

Using the code:

public class ParameterBuilder<T> {
  private String name;
  private T defaultValue;

  public static <T2> ParameterBuilder<T2> start(Class<T2> type) {
    return new ParameterBuilder<T2>();
  }
  // Other methods excluded for example
}

So the type of the input for the setDefaultValue method is defined by what's passed into the start method, just as I want.

But now I want to extend what's being passed into start() to contain a little more information. Essentially I want to pass in a "type" for the parameters I creating. Sometimes these parameters will be things like "email", "url" etc. The default value will still be of a known type (String in those cases), so I'd like to have something like:

ParameterBuilder.start(EMAIL).setName("email").setDefaultValue("[email protected]").build();
ParameterBuilder.start(URL).setName("website").setDefaultValue("http://www.somewhere.com").build();

Where at the moment EMAIL & URL are enums, containing amongst other things - the class of the default value. But if I go down this route, how would I instantiate the parameter builder?

public static <T2> ParameterBuilder<T2> start(ParameterType paramType) {
  Class<T2> type = paramType.getTypeClass();
  // How do I instantiate my ParameterBuilder with the right type?
}

If it can't be done using enums (which I can see being the case), does anyone have a suggestion for a different solution?

like image 289
Lee Theobald Avatar asked Nov 03 '22 17:11

Lee Theobald


1 Answers

I think you need one enum per class type (I don't see how you could have one enum cover several types and keep the thing working). In that case, a common generic interface could do what you want. You can then create some sort of factory to provide the enum constants if that helps.

This compiles:

static interface ParameterType<T> {}

static enum ParameterTypeEnum implements ParameterType<String> { EMAIL; }

public static void main(String[] args) {
    ParameterBuilder
           .start(ParameterTypeEnum.EMAIL)
           .setName("email")
           .setDefaultValue("[email protected]")
           .build();
}

public static class ParameterBuilder<T> {

    private String name;
    private T defaultValue;

    public static <T2> ParameterBuilder<T2> start(ParameterType<T2> paramType) {
        return new ParameterBuilder<T2>();
    }

    ParameterBuilder<T> setName(String name) {
        this.name = name;
        return this;
    }

    ParameterBuilder<T> setDefaultValue(T defaultValue) {
        this.defaultValue = defaultValue;
        return this;
    }

    void build() {}
}
like image 133
assylias Avatar answered Nov 13 '22 23:11

assylias