Come progettare una collezione iterabile ma immutabile (di sola lettura)

4

Il mio programma modella un torneo sportivo che ha uno o più eventi o categorie. La classe Event ha membri come giocatori o campi come List , così come alcuni dizionari che usano la classe Map .

Finora l'accesso pubblico a tali membri può essere fatto attraverso i rispettivi getter, ma ho capito che questa è una cattiva pratica perché consente modifiche attraverso l'oggetto di raccolta recuperato con il getter. E non vorrei questo.

Vorrei limitare il set di operazioni consentite su questi membri ed evitare la situazione descritta sopra.

Si potrebbe pensare che dichiarare questi membri come farebbe final , ma non è così. Questi membri possono ancora essere modificati, ma invece di farlo liberamente con i metodi nativi List o Map , è fatto tramite i metodi delle mie classi.

Quindi supponiamo di bloccare le serie di raccolte consentite su queste raccolte e di creare classi di wrapping per i miei elenchi e le mie mappe, quindi anziché avere questo:

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

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

Potrei avere qualcosa di simile:

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

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

Il nome delle classi dovrebbe probabilmente essere diverso, non riesco a pensare a qualcosa di meglio al momento.

Diciamo che vogliamo solo i metodi di lettura per queste classi. Quindi potremmo avere un metodo per ottenere le dimensioni e un altro per ottenere un particolare elemento della collezione interna:

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); }
}

Tuttavia, ora non riesco a ripetere gli elementi di una raccolta come normalmente farei:

for (Player player : players)
    System.out.println(player);

Anche se potrei usare get() e size() ma sembra un po 'rudimentale.

Cosa potrei fare per rendere queste collezioni iterabili mantenendo le regole di immutabilità del mio design? (Come ho detto non è strettamente immutabile, dal momento che puoi farlo usando i metodi pertinenti)

In generale, dovrei ripensare il mio design in modo diverso? Quello che sto cercando di fare ha senso? Potrei ottenerlo in modo diverso, in un modo migliore?

Credo che potrei dire che quello che sto cercando sono raccolte di sola lettura, vero?

    
posta dabadaba 20.04.2016 - 01:22
fonte

2 risposte

5

Sembra che tu abbia due requisiti qui:

  1. Event espone le raccolte, ma i chiamanti non possono modificare tali raccolte.

  2. Event può modificare le sue raccolte, ma solo attraverso la classe Event .

Sembra che tu debba utilizzare le raccolte immutabili, per esempio, java.util.Collections.unmodifiableList (Elenco elenco) . Tuttavia, non si desidera memorizzare una raccolta immutabile come stato in Event . Potrebbe funzionare in questo modo:

public class Event {

  private List<Player> players;

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

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

Ciò consente di modificare le collezioni attraverso Event , consentendo comunque ai chiamanti di ottenere un riferimento immutabile adatto per l'iterazione. La chiamata a Collections.unmodifiableList(players) avvolge la lista players e non copiala.

Se questo deve essere sicuro per i thread, ci sono ulteriori preoccupazioni da affrontare qui, ma non era un requisito. Sembra più che la tua classe Event abbia bisogno di gestire invarianti e integrità dei dati tra più raccolte che modellano gli stessi oggetti. Questa preoccupazione dovrebbe essere facilmente indirizzabile usando questa tecnica.

    
risposta data 20.04.2016 - 01:38
fonte
0

Hai due opzioni, oltre a far ruotare le tue - schiaffi una facciata su un elenco modificabile (come UnmodifiableList ) che non consente la modifica attraverso quell'interfaccia , o usa uno dei librerie di terze parti disponibili che sono veramente immutabili. Il problema dell'approccio alla facciata è che qualcuno (ad esempio una sottoclasse) potrebbe modificare l'elenco sottostante, interrompendo il contratto implicito presentando un UnmodifiableList . Un esempio di quest'ultimo è ImmutableList di Guava che è veramente immutabile, facendo intrinsecamente una copia difensiva quando inizializzato da un elenco.

    
risposta data 20.04.2016 - 06:21
fonte

Leggi altre domande sui tag