9

「パブリック最終フィールド」アプローチに従って、ゲームプロジェクトに取り組んでいるときに、Java で不変値オブジェクトをいじり始めました。

public class Team {
    public final String name, flag;

    public Team(String name, String flag) {
        this.name = name;
        this.flag = flag;
    }
}

これまでのところ、これはかなりうまく機能していますが、さまざまな状況でチームに関するさまざまな追加情報が必要です。たとえば、チームには試合中に色が設定されています。問題は、これらの一連の拡張情報を処理する最善の方法は何かということです。これはかなり一般的な質問であることはわかっていますが、不変オブジェクトを使い続けたいと思っており、それが解決策に影響を与える可能性があります。

ここに私が思いついたオプションがあります。それらのほとんどはおそらく「十分」ですが、今後の参考のために、それらに対する賛否両論を学びたいと思います。

オプション 1: すべてを 1 つのクラスにまとめる

public class Team {
    public final String name, flag, colorName;
    public final int colorRgb;

    public Team(String name, String flag, String colorName, int colorRgb) {
        this.name = name;
        this.flag = flag;
        this.colorName = colorName;
        this.colorRgb = colorRgb;
    }
}

これはすべての用途で 1 つのクラスしか必要としませんが、どのような追加データが期待/提供されるかをタイプベースで示すものはありません。

オプション 2: サブクラス化

public class TeamWithColor extends Team {
    public final String colorName;
    public final int colorRgb;

    public Team(String name, String flag, String colorName, int colorRgb) {
        super(name, flag);
        this.colorName = colorName;
        this.colorRgb = colorRgb;
    }
}

これにより、コンテンツベースの equals() 実装が不可能になる可能性があります。

オプション 3: 構成

public class TeamWithColor {
    public final Team team;
    public final String colorName;
    public final int colorRgb;

    public Team(Team team, String colorName, int colorRgb) {
        this.team = team;
        this.colorName = colorName;
        this.colorRgb = colorRgb;
    }
}

チーム データと追加データが頻繁に個別に変更される場合は、コピー/ボイラープレート コードが少なくなります。

オプション 4: Pair/Tuple (不変の Pair クラスを使用)

public class TeamColor {
    public final String colorName;
    public final int colorRgb;

    public Team(String colorName, int colorRgb) {
        this.colorName = colorName;
        this.colorRgb = colorRgb;
    }
}

Pair<Team, TeamColor> teamWithColor = Pair.create(team, teamColor);

... または、Team と TeamColor を結び付けるカスタム クラスを使用します。

私はオプション 3 または 4 に傾倒していますが、あなたの意見、議論、直感に興味があります :)

4

6 に答える 6

7

あなたが言ったように。チームはさまざまな状況で表示されます。これらの状況は、チームに追加の属性を与えるコンテキストです。

したがって、データを追加するさまざまなコンテキストごとにコンポジションを使用することをお勧めします。

public class TeamWithColor {
    public final Team team;
    public final TeamColor teamColor;

    public Team(Team team, TeamColor teamColor) {
        this.team = team;
        this.teamColor = teamColor;
    }
}

多分あなたは持っているでしょう:

public class TeamDuringOlimpics{
    public final Team team;
    public final TeamColor teamColor;
    public final TeamFlag teamFlag;

    public Team(Team team, TeamColor teamColor, TeamFlag teamFlagTeamFlag teamFlag) {
        this.team = team;
        this.teamColor = teamColor;
        this.teamFlag = teamFlag;
    }    
}
于 2012-08-04T17:24:45.020 に答える
2

Composition sounds like a good option for adding contextual data that is required to be mutable.

In Java immutable classes are usually marked final and cannot be extended. See String as an example. That rules out option number 2.

Be weary of using Pairs. There are many good reasons the Pair type has not been added to Java. In this case your data is better modeled by creating a new data type (i.e. thru composition).

Recommended best practices for creating immutable classes: http://www.javapractices.com/topic/TopicAction.do?Id=29

于 2012-08-04T17:23:51.297 に答える
1

不変クラスが継承可能である場合、またはタイプが可変である可能性のある側面が含まれている場合、いたずらに対するセキュリティはありません。同様に、「不変」インターフェースにはセキュリティがありません。同様に、オブジェクトが拡張可能な型のメンバーを持ち、オブジェクトがそれらのメンバーによって参照されるオブジェクト内の情報を含むと見なされる場合も同様です。それが問題かどうかはあなた次第です。不変のインターフェイスと拡張可能な可変クラスは、深く封印されたものよりもはるかに用途が広い場合があります。クラスが深く封印されない場合、部分的に封印してもセキュリティ上の利点はほとんどありません。

フィールドのセマンティクスが、問題のオブジェクトを含むのではなく識別することを指定している場合、深く不変のオブジェクトが可変型のフィールドを持つことができることに注意してください。たとえば、いくつかの変更可能なオブジェクトへの参照と、各オブジェクトの現在の状態の不変のコピーを含む「スナップショット」オブジェクトを持つと便利な場合があります。「スナップショット」オブジェクトは、スナップショットが生成されたときの状態に各オブジェクトを復元する方法を公開します。可変オブジェクトへのスナップショットの参照は純粋にそれらを識別するために存在し、それらのオブジェクトのアイデンティティは

私が .net で気に入っているパターンの 1 つは、Java でも動作するはずですが、IReadableFooandのようなインターフェイスを持つことIImmutableFooです。後者は前者を継承しますが、新しいメンバーは追加しません。インターフェイスIReadableFooには、そのプロパティを読み取るためのメンバーに加えて、AsImmutable()を返すメンバーが含まれている必要がありIImmutableFooます。このアプローチにより、コードは便利なときに変更可能な型を使用できるようになり、冗長な防御的コピーを最小限に抑えることができます (何かを保持したいコードはそれを呼び出す必要がありますAsImmutable()。問題のオブジェクトが変更可能な場合、そのアクションは不変のコピーを作成しますが、オブジェクトが既に不変であり、新しいコピーは必要ありません)。

于 2012-08-06T17:17:08.790 に答える
0

Decorator パターンをお勧めします。

public class TeamWithColor extends Team {
    public final Team team;
    public final String colorName;
    public final int colorRgb;

    public Team(Team team, String colorName, int colorRgb) {
        this.team = team;
        this.colorName = colorName;
        this.colorRgb = colorRgb;
    }
}

http://en.wikipedia.org/wiki/Decorator_pattern

于 2012-08-06T17:46:51.220 に答える
0

この情報を Team オブジェクトの外部に保持することを検討できます。たとえば、マップまたはマップを持つことができます

このようにして、新しいクラスを導入したり、既存のクラスを変更したりすることなく、多くの追加の値でオブジェクトを充実させることができます。さらに、他のオブジェクトの不変のプロパティを保持します。

于 2012-08-05T08:04:04.670 に答える