louis amoros
louis amoros

Reputation: 2546

Java Generics Type DSL with Builder Pattern

I try to create a DSL Java API with the Builder Pattern on Generics Type.

I have the following class:

public class Rule<T> {

  private Predicate<T> condition;

  public ConditionBuilder<T> when() {
    return new ConditionBuilder<>(this);
  }

  //setter and getter 

}

and the following ConditionBuilder class:

public class ConditionBuilder<T> {

  private Rule<T> parent;

  public ConditionBuilder(Rule<T> parent) {
    this.parent = parent;
  }

  public ConditionBuilder<T> condition1() {
    parent.setCondition(l -> l == 0); // I would like an Integer
    return this;
  }

  public ConditionBuilder<T> condition2() {
    parent.setCondition(l -> l.length() > 3); // I would like a String
    return this;
  }

}

I try to find a solution to set the Generic Type on the fly as an Integer (resp. String) for the condition1 (resp. condition2).

Is there any Pattern or solution to avoid doing instanceof checking ?

Upvotes: 1

Views: 333

Answers (2)

castletheperson
castletheperson

Reputation: 33496

I would use a factory pattern instead, because the builder pattern does not fit this situation. Using generics implies that you will accept any type, and so making condition require a specific type is a waste of the generics.

public class Rule<T> {
  private Predicate<T> condition;
  //setter and getter
}

class ConditionFactory {
  public static Rule<Integer> intCondition() {
    Rule<Integer> rule = new Rule<>();
    rule.setCondition(l -> l == 0);
    return rule;
  }

  public static Rule<String> strCondition() {
    Rule<Integer> rule = new Rule<>();
    rule.setCondition(l -> l.length() > 3);
    return rule;
  }
}

Upvotes: 0

Andy Turner
Andy Turner

Reputation: 140484

You can't do this with member methods on ConditionBuilder<T>, since you've already constructed parent before you invoke either of the conditionX methods. As such, you can't constrain the instance "after the fact".

The way I'd do this is by making the Rule<T> a parameter of a static method. Then you can use something like:

static ConditionBuilder<Integer> condition1(ConditionBuilder<Integer> parent) {
  parent.setCondition(l -> l == 0);
  return parent;
}

static ConditionBuilder<String> condition2(ConditionBuilder<String> parent) {
  parent.setCondition(l -> l.length() > 3);
  return parent;
}

Upvotes: 1

Related Questions