Creazione di riferimenti a oggetti bidirezionali e mantenimento dell'integrità dei dati

5

Ho due classi diverse; a Player e a Group . Devo essere in grado di interrogare un Player a cui Group s sono registrati ( player.getGroups() ), e quali Player s sono registrati rapidamente su Group ( group.getPlayers() ). La soluzione più semplice è che ogni Player tenga un elenco di Group s su cui è registrato, e ogni Group tiene un elenco di tutti i giocatori registrati a quel gruppo.

Questo introduce alcuni problemi di integrità dei dati (come faccio a garantire che se Player fa riferimento a Group , Group fa riferimento anche a Player ) e problemi su come aggiungere un Player a a% % co_de.

Una soluzione a quest'ultimo problema è avere un singolo metodo su Group o Player :

public class Player {

    // ...

    public void registerToGroup(Group group) {
        this.groups.add(group);
        group.addPlayer(player);
    }

    // ...

}

Funziona, ma introduce anche alcune conseguenze secondarie della modifica del Group che passi, cosa che potresti non aspettarti. Ma forse questo è il modo migliore (e relativamente semplice) per farlo?

Quali sono le migliori pratiche per questo tipo di problemi? Preferirei non dover cercare tra le liste e filtrare un certo Group per scoprire quale Player s a cui Group è registrato, e preferirei non mescolare i database in quanto è un progetto piuttosto piccolo ma deve essere in grado di espandersi senza troppi problemi.

    
posta Havsmonstret 03.07.2015 - 13:33
fonte

4 risposte

1

Prima di tutto, determina cosa è più comune nel tuo sistema - per elencare gruppi di un giocatore specifico o per elencare i giocatori di un gruppo specifico. A seconda di quale caso è più comune, implementarlo di conseguenza. Se si tenta di implementare entrambi allo stesso modo, si verificherà un calo di prestazioni per entrambi.

Quindi, l'ipotesi va Giocatore appartiene a un gruppo, quindi:

public class Group {
    public void AddPlayer(Player player) {

    }

    public void AddPlayers(IEnumerable<Player> player) {

    }
}

Ora che lo abbiamo tolto di mezzo.

public class Player {
    public Ienumerable<Group> GetRelevantGroups() {
        // Assuming you have some groups provider in this class. You should anyways.
        return this._groupsService.GetGroupsWithPlayer(this.Id);
    }
}

Usando entrambi:

// Adding a bunch of players to a group.
myGroup.Add(players);

// Getting all groups for specific player.
var playerGroups = player.GetRelevantGroups();
    
risposta data 03.07.2015 - 19:30
fonte
1

This works, but also introduces some side consequences of modifying the Group you pass, which you might not expect. But maybe this is the best (and relatively simple) way to do it?

Dal punto di vista del design, per mantenere entrambi gli elenchi sincronizzati ( se vuoi gestirlo in questo modo ) non è né la responsabilità di player né la% codice%. Puoi progettarlo con un mediatore (qui nella forma più semplice):

public class Group {

    List<Person> members;


    void addMember(Person p){
        members.add(p);
    }

}

public class Person {

    List<Group> groups;

    void addGroupMembership(Group g){
        groups.add(g);
    }
}

public class GroupingService {

    public void joinPersonToGroup(Person p, Group g){
        p.addGroupMembership(g);
        g.addMember(p);
    }

}

Ma oltre: c'è qualche ragione per implementarlo in questo modo?

    
risposta data 03.07.2015 - 21:32
fonte
1

Ho risolto questo problema una volta con qualcosa di simile:

class RelationshipManager {
    void addRelation(RelatableObject a, RelateableObject b);
    void removeRelation(RelatableObject a, RelatableObject b);

    List<C> getRelated(RelatableObject obj, Class<C> c);
}

Il RelationshipManager tiene traccia di quali oggetti sono correlati ad altri oggetti. Posso quindi effettuare richieste come:

relationshipManager.getRelated(player, Group.class);

Per ottenere tutti i gruppi per un determinato giocatore.

Puoi fare un ulteriore passo avanti e aggiungere metodi alla tua classe che chiamano questo:

class Player {

    List<Group> getGroups() {
       return relationshipManager.getRelated(this, Group.class);
    }
    void addGroup(Group group) {
       relationshipManager.addRelation(this, group);
    }
}

Nel mio caso, ero in Python, quindi in realtà ho fatto qualcosa del tipo:

class Player:
    groups = HasMany(Group)

e HasMany ha sovraccaricato il comportamento getter / setter predefinito di python per chiamare nel relationship manager. Ho anche un BelongsTo che trattava di singoli elementi invece di liste.

    
risposta data 04.07.2015 - 17:50
fonte
0

Il tuo problema più grande è che stai creando riferimenti circolari che possono portare a un mondo di problemi, da loop infiniti a perdite di memoria.
In un database devi creare un'entità separata (tabella) per contenere i riferimenti, tradotta in codice che è una classe con un riferimento sia a un giocatore che a un gruppo.
L'iterazione su una raccolta di quelli ti darà quindi tutti i giocatori in un gruppo o in tutti i gruppi a cui appartiene un giocatore, ma può diventare un'operazione costosa.

    
risposta data 03.07.2015 - 19:41
fonte

Leggi altre domande sui tag