読者です 読者をやめる 読者になる 読者になる

値を保持することを目的としたクラス

C# Java

一昨日の読書会で空のコンストラクタを強要することの是非から、イミュータブルについて、更に値を保持することを目的としたクラスで「使用不可能」や「まだどうなるか分からない」ことを表す方法について話が発展していった中で、自分がよく使う方法を紹介した。
とりあえず、その場ではかなり簡単な説明で済ませたので、もう少し詳しくここで補足しておきますね。


そのときに例として出ていた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を投げておくようにする。

*1:C#ではHasValueがtrueかどうかチェックする方がいいのかな

*2:C#ならInvalidOperationException、JavaならIllegalStateExceptionなど