値を保持することを目的としたクラス
一昨日の読書会で空のコンストラクタを強要することの是非から、イミュータブルについて、更に値を保持することを目的としたクラスで「使用不可能」や「まだどうなるか分からない」ことを表す方法について話が発展していった中で、自分がよく使う方法を紹介した。
とりあえず、その場ではかなり簡単な説明で済ませたので、もう少し詳しくここで補足しておきますね。
そのときに例として出ていたPointクラスをここでも使用するとして、まずは一番単純な例から。
C#では、
public sealed class Point { public readonly bool IsValid; public readonly int X; public readonly int Y; public Point(int x, int y) { X = x; Y = y; IsValid = true; } Point() { X = Y = -1; IsValid = false; } public static readonly Point InvalidPoint = new Point(); }
Javaでは、
public final class Point { public final boolean IS_VALID; public final int X; public final int Y; public Point(int x, int y) { X = x; Y = y; IS_VALID = true; } private Point() { X = Y = -1; IS_VALID = false; } public static final Point INVALID_POINT = new Point(); }
この例では、IsValidフィールドを参照することで、Pointオブジェクトが有効か無効かを判断できる。
また、IsValidフィールドは外部からは設定できず、このフィールドがfalseになるようなオブジェクトは(無理矢理作らない限り)InvalidPointのみとなる。
この例を更に発展させて、無効状態のPointオブジェクトのXやYを取得しようとした場合に例外を発生させるようにするには、
C#では、
public sealed class Point { readonly int? _X; readonly int? _Y; public Point(int x, int y) { _X = x; _Y = y; } Point() { _X = _Y = null; } public int X { get { return _X.Value; } } public int Y { get { return _Y.Value; } } public static readonly Point InvalidPoint = new Point(); }
Javaでは、
public final class Point { private final Integer X; private final Integer Y; public Point(int x, int y) { X = x; Y = y; } private Point() { X = Y = null; } public int getX() { return X; } public int getY() { return Y; } public static final Point INVALID_POINT = new Point(); }
のようにする。
この例ではコードを単純にするために、無効なPointオブジェクトを介して座標を取得しようとするとNullReferenceException/NullPointerExceptionが発生するけど、本来はフィールドがnullかどうかチェックして*1適切な例外*2を投げておくようにする。