値が範囲内にあるかを検証するRangeクラスを作ってみる

作成動機:
・既存のものが「n以上」なのか「nを超える」なのか、「m以下」なのか「n未満」なのか境界値が良くわからなかったので、設定可能なものを作ってみた。
ジェネリクスのsuperキーワードがいまだに消化できないのでComparableを使うコードを無理矢理書いてようと思った。

package sample;

public class Range<T extends Comparable<? super T>> {

	private final T min;
	private final T max;
	private final boolean containsMin;
	private final boolean containsMax;

	public Range() {
		this(null, null);
	}

	/**
	 * デフォルトで _min <= val < _max の検索
	 */
	public Range(T _min, T _max) {
		this(_min, true, _max, false);
	}

	public Range(T _min, boolean _containsMinVal,
			T _max,	boolean _containsMaxVal) {
		min = _min;
		containsMin = _containsMinVal;
		max = _max;
		containsMax = _containsMaxVal;
	}

	public boolean contains(T val) {
		return evalMin(val) && evalMax(val);
	}

	private boolean evalMin(T val) {
		if (min == null)
			return true;
		return containsMin ? min.compareTo(val) <= 0 
                                   : min.compareTo(val) < 0;
	}

	private boolean evalMax(T val) {
		if (max == null)
			return true;
		return containsMax ? max.compareTo(val) >= 0 
                                   : max.compareTo(val) > 0;
	}
}

検証コード

package sample;

import junit.framework.TestCase;

public class RangeTest extends TestCase {

	public void testString() {
		
		Range<String> range = null;

		range = new Range<String>("1", "4");
		assertFalse(range.contains("0"));
		assertTrue(range.contains("1"));
		assertTrue(range.contains("2"));
		assertTrue(range.contains("3"));
		assertFalse(range.contains("4"));
		assertFalse(range.contains("5"));
		
		range = new Range<String>("1", false, "4", false);
		assertFalse(range.contains("0"));
		assertFalse(range.contains("1"));
		assertTrue(range.contains("2"));
		assertTrue(range.contains("3"));
		assertFalse(range.contains("4"));
		assertFalse(range.contains("5"));
		
		range = new Range<String>("1", false, "4", true);
		assertFalse(range.contains("0"));
		assertFalse(range.contains("1"));
		assertTrue(range.contains("2"));
		assertTrue(range.contains("3"));
		assertTrue(range.contains("4"));
		assertFalse(range.contains("5"));
		
		range = new Range<String>("1", true, "4", true);
		assertFalse(range.contains("0"));
		assertTrue(range.contains("1"));
		assertTrue(range.contains("2"));
		assertTrue(range.contains("3"));
		assertTrue(range.contains("4"));
		assertFalse(range.contains("5"));
		
		range = new Range<String>(null, true, "4", true);
		assertTrue(range.contains("0"));
		assertTrue(range.contains("1"));
		assertTrue(range.contains("2"));
		assertTrue(range.contains("3"));
		assertTrue(range.contains("4"));
		assertFalse(range.contains("5"));
		
		range = new Range<String>("1", true, null, true);
		assertFalse(range.contains("0"));
		assertTrue(range.contains("1"));
		assertTrue(range.contains("2"));
		assertTrue(range.contains("3"));
		assertTrue(range.contains("4"));
		assertTrue(range.contains("5"));
	}
}

・追加で境界値なしも設定できるようにした。インスタンス生成時にnullを指定すれば境界値なし。
・デフォルトは「min以上max未満」。個人的にこれが利用頻度が高そうな気がしたので。

2008-06-07 23:21 追記
既存の実装では「min以上max以下」が多いので、そちらに合わせた方がベターだと思います。

・とりあえずStringとIntegerで検証した。


・Comparableの部分の宣言はけっきょく本のコピペ。やはり理解できてない。
・たぶんちゃんと探せば似たクラスは既にあるんじゃないでしょうか。(自分はGoogleコードサーチで少ししか探してないです)
・未テストだけど日付チェックとかも活用できそう。