Range

From EggeWiki

Jump to: navigation, search

Martin Fowler has written about the [Range Base Pattern] for representing a range of values. Here's a generic base class I wrote in Java which has the same basic functionality. I usually subclass this and add type specific methods.

/**
 * A generic range.  I would prefer to define this as Range<E extends Comparable<? super E>>,
 * but then pre 1.5 types can't be used with this.
 * Additionally, you run into hell when you have Base implements Comparable<Base> and want to have
 * Derived extends Base.  Derived can't implement Comparable<Derived> because it's already defined differently
 * in the base class.
 */
public class Range<E extends Comparable> {
    protected final E min;
    protected final E max;
 
    public Range(E min, E max) {
        GuardHelper.notNullMultiple(min, max);
        validate(min, max);
        this.min = min;
        this.max = max;
    }
 
    protected void validate(E min, E max) {
        if (min.compareTo(max) > 0) {
            throw new IllegalArgumentException(min + " < " + max);
        }
    }
 
    public boolean contains(E value) {
        return value != null && min.compareTo(value) <= 0
                && max.compareTo(value) >= 0;
    }
 
    public E getMinimum() {
        return min;
    }
 
    public E getMaximum() {
        return max;
    }
 
    public int hashCode() {
        return min.hashCode() + max.hashCode();
    }
 
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
 
        Range range = (Range) o;
 
        return max.equals(range.max) && min.equals(range.min);
    }
 
 
    @Override
    public String toString() {
        return min + ".." + max;
    }
}

And of course the unit test

public class RangeUnitTest extends UnitTestCase {
    public void testContains() {
        Range<Integer> range = new Range<Integer>(3, 5);
        assertFalse(range.contains(2));
        assertTrue(range.contains(3));
        assertTrue(range.contains(4));
        assertTrue(range.contains(5));
        assertFalse(range.contains(6));
    }
 
    public void testCtor() {
        try {
            new Range<Integer>(5, 3);
            failIfNoExceptionThrown();
        } catch (IllegalArgumentException e) {
            pass();
        }
    }
}
Personal tools