1

Let's say we have an abstract class that defines a constructor taking an integer where a precondition checks if the integer is within a list of possible values:

public abstract class Value {
   protected int value;
   protected static List<Integer> possibleValues;

   public Value(int val) {
       if (!possibleValues.contains(val))
           throw new IllegalArgumentException("Illegal value");
       value = val;
   }
}

But we want to initialize that list in Value's child classes because each define their own list of possible values.

I guess I could do a static block adding members to possibleValues, although I dislike static blocks. But that does not mean that all child classes would stop pointing to the same list of possible values.

How can I force the child classes to define a list of possible values and do the precondition check without facing the issues I described?

Edit: so we could say I want to inherit the behavior but not the variable itself.

dabadaba
  • 9,064
  • 21
  • 85
  • 155
  • Why don't you define an abstract `isValid` method that child classes fill in? Or make Value templatized with a ValueChecker class that derived classes provide? – Robert May 15 '16 at 18:21
  • I'd suggest using a Set instead of a List. Also, using a factory pattern would be more usable and cleaner. – Ioannis Deligiannis May 15 '16 at 18:23

2 Answers2

2

How about:

public abstract class Value {
   protected int value;
   protected abstract List<Integer> getPossibleValues();

   public Value(int val) {
       if (!getPossibleValues().contains(val))
           throw new IllegalArgumentException("Illegal value");
       value = val;
   }
}

Your subclasses will be forced to implement getPossibleValues().

Burkhard
  • 14,596
  • 22
  • 87
  • 108
  • 2
    The general idea is nice, but here you have a constructor calling a subclass overridden method which is a bad idea: http://stackoverflow.com/questions/3404301/whats-wrong-with-overridable-method-calls-in-constructors – Oliver Dain May 15 '16 at 18:23
  • @dabadaba: it was just an idea from the top of my head. As Oliver pointed out it is not the best idea and a better design can surely be found. – Burkhard May 15 '16 at 18:31
  • @Oliver It will do so far, because the parent class won't be inherited. I have absolute control over that. But out of curiosity, what alternative would you suggest? – dabadaba May 15 '16 at 22:34
  • @dabadaba see the first solution in my edited answer. Basically the base class constructor has a required parameter which is the list of legal integers. Subclasses then must pass such a list so they can't forget and it can come from a static in each of those subclass which is, I think, what you were after. – Oliver Dain May 15 '16 at 22:41
  • @Oliver wouldn't you agree that's a bit of an overkill **if** this particular case, as I described before, will not expect any other child classes than the ones I already defined? – dabadaba May 15 '16 at 22:46
  • @dabadaba I'm a bit confused. In your original question you talk about "child classes" so I assume that means that your `Value` class is going to be inherited by child classes. In fact, the answer here works only if there's a subclass that implements `getPossibleVaues`. I don't understand what, "the parent class won't be inherited" means. The solution here isn't safe: there's many ways a subclass can implement `getPossibleValues` that will result in failure. The alternative below is the same amount of code so I don't know why it feels like "overkill". It is, however, safe. – Oliver Dain May 15 '16 at 23:28
0

How about something like:

public abstract class Value {
    int value;

    protected Value(int val, List<Integer> possibleValues) {
        if (!possibleValues.contains(val)) {
            throw IllegalArgumentException();
        }
        this.value = val;
    }
}

class SubValue extends Value {
    private static final List<Integer> possibleValues = ...;
    SubValue(int val) {
        super(val, possibleValues);
    }
}
Oliver Dain
  • 9,617
  • 3
  • 35
  • 48
  • Why would they remember to do that? The whole point of my design was to include the behavior (precondition check) in the parent class so the child classes wouldn't have to do it. – dabadaba May 15 '16 at 18:29
  • @dabadaba agreed. Just updated the answer with what I think is a better option. – Oliver Dain May 15 '16 at 18:32