2010-05-06 14 views
8

qual è il modo migliore per modellare la relazione molti-a-molti?Relazione molti-a-molti in oop

Diciamo che abbiamo un due classi, squadra e Player

  • un dato Player può essere in più squadra s
  • qualsiasi squadra può avere come molti Player s come preferiscono

mi piace chiamare i metodi come

  • playerX.getTeamList() per ottenere l'elenco di tutti gli team s lui/lei è in
  • teamY.getPlayerList() per ottenere l'elenco di tutti gli Player s nella squadra

(o avere qualche altro modo per farlo in modo efficace)

mi viene in mente tw o modi per farlo, ma non si sentono come buoni pattumieri. puoi pensare a dei buoni modi, forse un patten di design?

risposta

2

va bene, Player ha una raccolta di Team e Team ha raccolta di Player. È necessario prestare attenzione all'integrità nelle operazioni di aggiunta/rimozione, perché non sono "atomici"

3
public class Player 
{ 
    public Team[] Teams {get;set;} 
} 

public class Team 
{ 
    public Player[] Players {get;set;} 
} 

Perfettamente ragionevole.

+2

Stai trascurando il vero problema, che è la necessità di mantenere i loro contenuti sincronizzati. Un modo per garantirlo è implementarne uno in termini di altro. – reinierpost

+0

@rein Chi dice che è il "vero problema"? Non possiamo dire quale sia il problema se non sappiamo come viene scritta la sua applicazione. Non ha specificato se si tratta di modelli (droni privi di logica riempiti di dati e inviati sulla loro strada) o entità (classi che dispongono di strutture avanzate che supportano il caricamento lento e altri paradigmi di archiviazione) o qualcos'altro. Il modello più semplice è che questi tipi siano istanziati da un repository o da un livello di storage di qualche tipo responsabile di tutte le operazioni che riguardano team e giocatori. – Will

+1

BACIO, finché non puoi. – Will

2

Vale la pena distinguere l'atmosfera API dall'attuazione effettiva.

Mentre è logico che entrambe le classi espongano tale raccolta (ad esempio get * List()), non devono necessariamente contenere l'istanza della raccolta.

Ti suggerisco di creare una classe League o qualcosa di simile, che contiene una sorta di dizionario di mappatura giocatore-squadra privato. Le aggiunte a queste "raccolte" complete dell'istanza Team/Player devono chiamare i metodi interni sull'istanza League per aggiornare i mapping. In questo modo, si mantengono gli aggiornamenti atomici (come suggerito da Andrey) e senza errori.

0

IMHO quello che descrivi è il modo "naturale" per OO. Il tuo XXX.getXXXList() è l'interfaccia per le tue classi. E per un numero limite di classi che sarebbe la strada giusta.

Considerare che esistono 1000 classi che possono essere "interconnesse". Può essere interessante avere alcuni ManyToManyManager per rilasciare un oggetto, aggiungere un altro oggetto agli oggetti correlati di un oggetto e recuperare l'elenco di tutti gli oggetti relazionati a un altro. Sarebbe una sorta di delega contro l'implementazione.

Shure se si delegano i vostri molti a molti a un'altra istanza il modello di oggetto non riflette più quella relazione molti a molti.

1

La risposta di Will è corretta. Tuttavia, per gestire la sincronizzazione, probabilmente inizierei con ObservableCollection. Avere un lato della relazione è il "maestro" che tiene traccia di aggiunge/rimuove dall'altra parte e si occupa della sincronizzazione.

Tuttavia, tenere presente che se un oggetto è iscritto a eventi sull'altro, si tratta di un riferimento forte che impedirà la garbage collection. Molto probabilmente lasceranno spazio allo stesso tempo, quindi questo è un non-problema, ma è qualcosa di cui essere a conoscenza.

+0

Hmm ... dove abbiamo visto questo problema prima :) – LBushkin

7

La relazione tra giocatori e squadre forma Bipartite Graph. Aspettando commenti (e downvotes?)! Sono OOD noob.

class MyPlayer 
    { 
     public string Name { get; set; } 

     public MyPlayer(string n) 
     { 
      Name = n; 
     } 
    } 

    class MyTeam 
    { 
     public string Name { get; set; } 

     public MyTeam(string n) 
     { 
      Name = n; 
     } 
    } 

    class PlayerTeamPair 
    { 
     public MyPlayer Player { get; set; } 
     public MyTeam Team { get; set; } 

     public PlayerTeamPair(MyPlayer p,MyTeam t) 
     { 
      Player = p; 
      Team = t; 
     } 
    } 

    class PlayerTeamBipartiteGraph 
    { 
     public List<PlayerTeamPair> Edges { get; set; } 

     public PlayerTeamBipartiteGraph() 
     { 
      Edges = new List<PlayerTeamPair>(); 
     } 

     public void AddPlayerAndTeam(MyPlayer p, MyTeam t) 
     { 
      Edges.Add(new PlayerTeamPair(p, t)); 
     } 

     public List<MyTeam> GetTeamList(MyPlayer p) 
     { 
      var teams = from e in Edges where e.Player == p select e.Team; 
      return teams.ToList<MyTeam>(); 
     } 

     public List<MyPlayer> GetPlayerList(MyTeam t) 
     { 
      var players = from e in Edges where e.Team == t select e.Player; 
      return players.ToList<MyPlayer>(); 
     } 

    } 


    class Program 
    { 
     static void Main(string[] args) 
     { 
      var G = new PlayerTeamBipartiteGraph(); 

      MyPlayer a = new MyPlayer("A"); 
      MyPlayer b = new MyPlayer("B"); 
      MyPlayer c = new MyPlayer("C"); 
      MyPlayer d = new MyPlayer("D"); 

      MyTeam t1 = new MyTeam("T1"); 
      MyTeam t2 = new MyTeam("T2"); 

      G.AddPlayerAndTeam(a, t1); 
      G.AddPlayerAndTeam(b, t1); 
      G.AddPlayerAndTeam(c, t1); 
      G.AddPlayerAndTeam(b, t2); 
      G.AddPlayerAndTeam(d, t2); 

      G.GetTeamList(b).ForEach(t => Console.Write(" {0} ",t.Name)); 
      Console.WriteLine(); 
      G.GetPlayerList(t2).ForEach(p => Console.Write(" {0} ",p.Name)); 
      Console.WriteLine(); 
     } 
    } 
1

Dividere la relazione molti-a-molti in due uno-a-molti. Rende tutto molto più semplice.