web-dev-qa-db-ja.com

反復可能だが不変(読み取り専用)コレクションを設計する方法

私のプログラムは、1つまたは複数のイベントまたはカテゴリを持つスポーツトーナメントをモデル化しています。クラスEventには、Listとしてプレーヤーやコートなどのメンバーがあり、クラスMapを使用するいくつかの辞書があります。

これまでのところ、これらのメンバーにパブリックにアクセスすることは、それぞれのゲッターを介して行うことができますが、ゲッターで取得したコレクションオブジェクトを介して変更を許可するため、これは悪い習慣であることに気付きました。そして、私はこれを望んでいません。

これらのメンバーで許可される操作のセットを制限し、上記の状況を回避したいと思います。

これらのメンバーをfinalのように宣言するだけだと思う​​かもしれませんが、そうではありません。これらのメンバーは引き続き変更できます。ネイティブのListまたはMapメソッドを使用して直接自由に変更するのではなく、クラスのメソッドを使用して変更します。

したがって、これらのコレクションで許可されている一連の操作のコレクションをクランプし、リストとマップのラッピングクラスを作成するとします。

_private List<Player> players;
private List<Court> courts;

private Map<Player, List<Timeslot>> playersUnavailable;
_

私は次のようなものを持つことができます:

_private CustomList<Player> players;
private CustomList<Court> courts;

private CustomMap<Player, List<Timeslot>> playersUnavailable;
_

クラスの名前はおそらく異なる必要があるでしょう。今のところ、これ以上良いものは思いつきません。

これらのクラスのリーダーメソッドだけが必要だとします。したがって、サイズを取得するメソッドと、内部コレクションの特定の要素を取得するメソッドを持つことができます。

_public class CustomList<T> {
    private final List<T> list;
    public CustomList<T>(List<T> l) { list = l; }
    public int size() { return list.size(); }
    public int get(int i) { return list.get(i); }
}
_

ただし、今は通常のようにコレクションの項目を反復処理できません。

_for (Player player : players)
    System.out.println(player);
_

get()size()を使用することもできますが、少し初歩的な感じがします。

これらのコレクションを反復可能にするために何ができますか?ただし、デザインの不変性のルールを維持しますか? (私が言ったように、適切なメソッドを使用してそれを行うことができるので、それは厳密に不変性ではありません)

全体として、デザインを別の方法で考え直す必要がありますか?私がやろうとしていることは理にかなっていますか?もっと良い方法で別の方法で達成できますか?

私が探しているのは読み取り専用のコレクションだと言えるのではないでしょうか。

3
dabadaba

ここには2つの要件があるようです。

  1. Eventはコレクションを公開しますが、呼び出し元はそれらのコレクションを変更できません。

  2. Eventはそのコレクションを変更できますが、Eventクラスを介してのみ変更できます。

不変の collections を使用する必要があるようです。たとえば、 Java.util.Collections.unmodifiableList(List list) のようになります。ただし、不変コレクションを状態としてEventに保存する必要はありません。次のように機能します。

_public class Event {

  private List<Player> players;

  public List<Player> getPlayers() {
    return Collections.unmodifiableList(players);
  }

  public void addPlayer(Player p) {
    players.add(p);
  }
}
_

これにより、Eventを使用してコレクションを変更できる一方で、呼び出し元は反復に適した不変の参照を取得できます。 Collections.unmodifiableList(players)を呼び出すと、リストplayersがラップされ、notでコピーされます。

これをスレッドセーフにする必要がある場合は、ここで対処する追加の懸念事項がありますが、それは要件ではありませんでした。 Eventクラスは、同じオブジェクトをモデル化する複数のコレクション間の不変条件とデータの整合性を処理する必要があるようです。この問題は、この手法を使用して簡単に対処できます。

5
user22815

自分でロールする以外に、2つの選択肢があります-変​​更可能なリスト(UnmodifiableListなど)の上にファサードをたたき、そのインターフェースからの変更を許可しません、または真に不変の使用可能なサードパーティライブラリのいずれかを使用します。ファサードアプローチの問題は、誰か(たとえば、サブクラス)が基礎となるリストを変更し、UnmodifiableListを提示することによって暗示されている規約に違反する可能性があることです。後者の例は、Guavaの ImmutableList です。これは真に不変であり、リストから初期化されると本質的に防御コピーを作成します。

0
Hank D