連載

Javaオブジェクトモデリング

第5回
静的モデル:
データ型におけるUMLとJavaのマッピング(1)

浅海智晴
2002/10/1

■■3.4 バリューオブジェクトの導入■■

 それでは、“データ型”として利用できるオブジェクトとは、どのようなものでしょうか。もちろんこれは「値」として扱うことができるということです。「値を表現するためのオブジェクト」は、値を扱う場合と同じ使い勝手を提供することが必要です。このような性質を持つオブジェクトを本連載では「バリューオブジェクト」と呼ぶことにします。バリューオブジェクトであるためには、以下の要件を満たすことが必要となります。

  • 変数への代入に特別な配慮がいらないこと
  • 内容による比較ができること

 大事なところなので、ちょっと細かく見ていきます。

●3.4.1 変数の更新(プリミティブ型)

 Javaにおいて、オブジェクトを格納する変数は、正確にはオブジェクトへの参照を格納しています。「変数への代入に特別な配慮がいらないこと」とは、オブジェクトへの参照をそのまま代入しても、矛盾が起こらないということです。例を使って説明しましょう。リスト1のSpaceShipは、2次元座標上での場所のデータをインスタンス変数x、yに格納しています。SpaceShipの移動はmoveメソッドを使って行います。moveメソッドは、引数で渡された値をそのままインスタンス変数に代入しています。また、SpaceShipの現在位置はprintメソッドでコンソールに表示することができます。

リスト1 SpaceShip.java
public class SpaceShip {
    private int x;
    private int y;
    

public void move(int x, int y) {
        this.x = x;
        this.y = y;
    }
    public void print() {
        System.out.println("x = " + x + ", y = " + y);
    }
}

 テストのためのプログラムClientで、SpaceShipの動作を確認します(リスト2)。Clientはmoveメソッドを用いてSpaceShipを移動させた後、SpaceShipの場所をコンソールに表示させています。プログラムで少し変わっているところは、SpaceShipの移動後、SpaceShipの移動に用いた変数xと変数yの内容を更新している点です。

リスト2 Client.java
public class Client {
    public static void main(String[] args) {
        SpaceShip ship = new SpaceShip();
        int x = 100;
        int y = 200;
        ship.move(x, y);
        x = 200;
        y = 300;
        ship.print();
    }
}

 Clientの動作は以下のようになります(実行結果1)

実行結果1
$ java Client
x = 100, y = 200

 当たり前ですが、SpaceShipのmoveメソッドを呼んだ後で、変数の値を変えてもSpaceShipには影響を与えません。

●3.4.2 変数の更新(オブジェクト)

 次はSpaceShipの位置をプリミティブ型ではなく、2次元座標上の位置を表現するオブジェクトPoint(リスト3)を使って実現します。

リスト3 Point.java
public class Point {
    public int x;
    public int y;
}

 Point版のSpaceShipは、リスト4となります。moveメソッドは、引数で渡された値をそのままインスタンス変数に代入しています。

リスト4 SpaceShip.java(Point版)
public class SpaceShip {
    private Point position;

    public void move(Point position) {
        this.position = position;
    }
    

public void print() {
        System.out.println("x = " + position.x + ", y = " + position.y);
    }
}

 テストのためのプログラムClientはリスト5となります。moveメソッドの呼び出し前に、オブジェクトに値を設定。moveメソッドの呼び出しの後に、オブジェクトの値を更新しています。

リスト5 Client.java
public class Client {
    public static void main(String[] args) {
        SpaceShip ship = new SpaceShip();
        Point point = new Point();
        point.x = 100;
        point.y = 200;
        ship.move(point);
        point.x = 200;
        point.y = 300;
        ship.print();
    }
}

 Clientの動作は以下のようになります(実行結果2)

実行結果2
$ java Client
x = 200, y = 300

 今度は、このように値が変わってしまいました。本来は“x = 100、y = 200”となるのが想定された動作ですが、残念ながら“x = 200、y = 300”という結果となってしまいました。このように、データをプリミティブ型の変数を用いて処理しているときには発生しなかった問題が、オブジェクトを使うと発生してきます。

●3.4.3 データの比較(プリミティブ型)

 もう1つの問題は、データの比較です。まずプリミティブ型のデータの場合を見てみましょう。今度のSpaceShipはリスト6となります。isHitメソッドによって、現在の位置が、指定された座標にヒットしているかを調べることができます。

リスト6 SpaceShip.java
public class SpaceShip {
    private int x;
    private int y;

    public void move(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public boolean isHit(int x, int y) {
        return (this.x == x && this.y == y);
    }
}

 この場合の、isHitメソッドの実装は値をそのまま比較すればよいだけです。動作確認のためのプログラムはリスト7となります。

リスト7 Client.java
public class Client {
    public static void main(String[] args) {
        SpaceShip ship = new SpaceShip();
        int x1 = 100;
        int y1 = 200;
        ship.move(x1, y1);
        int x2 = 100;
        int y2 = 200;
        System.out.println(ship.isHit(x2, y2));
    }
}

 それでは、実行してみましょう(実行結果3)

実行結果3
$ java Client
true

 当然ですが、無事動作しました。

●3.4.4 データの比較(オブジェクト)

 次は、オブジェクトを使った場合です。オブジェクトPointは先ほど使ったものと同じです(リスト8)

リスト8 Point.java
public class Point {
    public int x;
    public int y;
}

 SpaceShipは、位置データの格納にオブジェクトPointを使うように変更されています(リスト9)

リスト9 SpaceShip.java
public class SpaceShip {
    private Point position;

    public void move(Point position) {
        this.position = position;
    }

    public boolean isHit(Point position) {
        return (this.position.equals(position));
    }
}

 動作確認のためのプログラムはリスト10となります。 変数point1と変数point2は、いずれもオブジェクトPoint型の変数です。まず変数point1に値を設定し、これを用いてSpaceShipのmoveメソッドを呼び出しています。次に変数point1に、変数point2に設定したものと同じ値を設定し、これを用いてSpaceShipのisHitメソッドを呼び出します。

リスト10 Client.java
public class Client {
    public static void main(String[] args) {
        SpaceShip ship = new SpaceShip();
        Point point1 = new Point();
        point1.x = 100;
        point1.y = 200;
        ship.move(point1);
        Point point2 = new Point();
        point2.x = 100;
        point2.y = 200;
        System.out.println(ship.isHit(point2));
    }
}

 それでは実行してみましょう(実行結果4)

実行結果4
$ java Client
false

 今度の結果は期待どおりにはなりませんでした。本来はtrueになってほしいところですが、falseが表示されました。同じ内容を持つデータを比較したのにもかかわらず、比較の実行結果は“同じではない”となったわけです。

 以上、今回はJavaにおけるデータ型の扱いについて説明しました。UMLのデータ型をそのままJavaの世界に持ってくるとクラス図が繁雑になってしまうという問題があります。この問題を解決するために“データ型”という概念を導入しました。

 次回は、“データ型”を軸にJavaによるデータ型の実装の戦略、実装例を解説していきます。

2/2

Javaオブジェクトモデリング 第5回
  オブジェクトとデータ
バリューオブジェクトの導入


Javaオブジェクトモデリング INDEX


IT Architect 連載記事一覧


この記事に対するご意見をお寄せください managemail@atmarkit.co.jp

「ITmedia マーケティング」新着記事

「AIによる顧客体験(CX)向上」に懐疑的な見方が広がる――Qualtrics調査
Qualtricsが実施した年次グローバル調査から見えたカスタマーエクスペリエンス(CX)の現...

2025年のSNS大予測 AIの時代に「ソーシャル」はどう変わる?
もういくつ寝ると2025年……と数えるのはさすがに気が早いかもしれないが、それでも2024...

SEOで陥りがちな失敗は「アルゴリズム変更に対応できなかった」が最多に 原因は?
SEOの成功には何が必要なのか、失敗経験者へのアンケートで浮き彫りになったこととは……。