Отношения Many-many в ООП

что лучший способ состоит в том, чтобы смоделировать many-many отношения?

позволяет говорят, что у нас есть два классы, Команда и Игрок

  • любой данный Плеер может быть в нескольких Командах s
  • у любой Команды может быть столько Плеер s, сколько им нравится

Мне нравится называть методы как

  • playerX.getTeamList() для получения списка всей Команды s, он находится в
  • teamY.getPlayerList() получить список всего Плеера s в команде

(или имейте некоторый другой способ сделать это эффективно),

Я могу думать о двух способах сделать это, но они просто не делают чувствует себя подобно хорошим башмакам ООП. можно ли думать о каких-либо хороших путях, возможно, башмак дизайна?

8
задан Manu 6 May 2010 в 12:20
поделиться

7 ответов

Отношения между игроками и командами образуют двудольный граф. Жду комментариев (и даунвотов?)! Я OOD нооб.

    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();
        }
    }
6
ответ дан 5 December 2019 в 10:01
поделиться
public class Player
{
  public Team[] Teams {get;set;}
}

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

Совершенно разумно.

3
ответ дан 5 December 2019 в 10:01
поделиться

IMHO то, что вы описываете - это "естественный" путь для OO. Ваш XXX.getXXXList() - это интерфейс к вашим классам. И для ограниченного числа классов это будет правильный путь.

Представьте, что есть 1000 классов, которые могут быть "взаимосвязаны". Тогда может быть интересно иметь некий ManyToManyManager, который может закинуть объект, добавить другой объект к связанным объектам объекта и получить список всех объектов, связанных с другим. Это было бы своего рода делегирование против реализации.

Шуре, если вы делегируете ваше отношение "многие-ко-многим" другому экземпляру, ваша объектная модель больше не отражает это отношение "многие-ко-многим".

0
ответ дан 5 December 2019 в 10:01
поделиться

Разделите отношение «многие ко многим» на два отношения «один ко многим». Все становится намного проще.

3
ответ дан 5 December 2019 в 10:01
поделиться

все в порядке, Player имеет коллекцию Team и Team имеет коллекцию Player. Вам нужно быть осторожным с целостностью в операциях добавления/удаления, потому что они не являются "атомарными"

2
ответ дан 5 December 2019 в 10:01
поделиться

Стоит отличать ощущение API от реальной реализации.

Хотя для обоих классов имеет смысл предоставлять такую ​​коллекцию (например, get * List ()), они не обязательно должны содержать экземпляр коллекции.

Я предлагаю вам создать класс League или что-то в этом роде, которое будет содержать своего рода частный словарь сопоставлений игроков и команд. Добавления к этим «коллекциям» в экземпляре Team / Player должны вызывать внутренние методы в экземпляре League для обновления сопоставлений. Таким образом, вы сохраняете атомарные обновления (как предложил Андрей) и безошибочные.

2
ответ дан 5 December 2019 в 10:01
поделиться

Ответ от Уилла правильный. Однако, чтобы разобраться с синхронизацией, я бы, вероятно, начал с ObservableCollection. Пусть одна сторона отношения будет "ведущей", которая отслеживает добавления/удаления на другой стороне и занимается синхронизацией.

Однако имейте в виду, что если один объект подписывается на события другого, то это сильная ссылка, которая предотвратит сборку мусора. Скорее всего, они будут покидать область видимости одновременно, так что это не проблема, но об этом следует помнить.

1
ответ дан 5 December 2019 в 10:01
поделиться