Отношение многие ко многим в oop - PullRequest
8 голосов
/ 06 мая 2010

Как лучше всего моделировать отношения «многие ко многим»?

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

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

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

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

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

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

Ответы [ 7 ]

6 голосов
/ 06 мая 2010

Отношения между игроками и командами формируются Двухсторонний график . Жду комментариев (и голосов?)! Я 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();
        }
    }
3 голосов
/ 06 мая 2010
public class Player
{
  public Team[] Teams {get;set;}
}

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

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

2 голосов
/ 07 мая 2010

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

2 голосов
/ 06 мая 2010

Стоит отличить чувство API от фактической реализации.

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

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

2 голосов
/ 06 мая 2010

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

1 голос
/ 06 мая 2010

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

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

0 голосов
/ 06 мая 2010

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

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

Конечно, если вы делегируете свой «многие ко многим» другому экземпляру, ваша объектная модель больше не отражает это отношение «многие ко многим».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...