Manu
Manu

Reputation: 502

Many-to-many relationship in oop

what is best way to model many-to-many relationship?

lets say we have a two classes , Team and Player

I like to call methods like

(or have some other way to do this effectively)

I can think of two ways of doing this , but they just don't feels like good oop pattens. can you think of any good ways , perhaps a design patten ?

Upvotes: 10

Views: 7199

Answers (7)

Lotus Notes
Lotus Notes

Reputation: 6363

Split the many-to-many relationship into two one-to-many's. Makes everything a lot more simple.

Upvotes: 4

Pratik Deoghare
Pratik Deoghare

Reputation: 37172

Relationship between players and teams form Bipartite Graph. Expecting comments(and downvotes?)! I am 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();
        }
    }

Upvotes: 6

RationalGeek
RationalGeek

Reputation: 9599

The answer from Will is correct. However, to deal with syncing, I would probably start with ObservableCollection. Have one side of the relationship be the "master" which keeps track of adds / removes on the other side and deals with syncing.

However, be aware that if one object is subscribing to events on the other that this is a strong reference that will prevent garbage collection. Most likely they will be leaving scope at the same time so this is a non-issue but it is something to be aware of.

Upvotes: 1

PeterMmm
PeterMmm

Reputation: 24630

IMHO what you describe is the "natural" way for OO. Your XXX.getXXXList() is the interface to your classes. And for a limit number of classes that would be the right way.

Consider there are 1000 classes that can be "interconnected". Than it may be interesting to have some ManyToManyManager to drop in an object, add another object to the related objects of an object and retrieve the list of all objects releated to another. That would be some sort of delegation vs. implementation.

Shure if you delegate your many-to-many to another instance your object model do not reflect that many-to-many relation anymore.

Upvotes: 0

user286353
user286353

Reputation:

It's worth to distinguish the API feel from actual implementation.

While it makes sense for both classes to expose such a collection (e.g. get*List()), they don't neccessarily have to hold the instance of the collection.

I suggest you create a League class or something alike, that holds some sort of a private player-team mappings dictionary. Additions to those 'collections' thorough the Team/Player instance, should call internal methods on the League instance to update the mappings. This way, you keep updates atomic (as Andrey suggested) and error free.

Upvotes: 2

user1228
user1228

Reputation:

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

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

Perfectly reasonable.

Upvotes: 3

Andrey
Andrey

Reputation: 60065

it is fine, Player has a collection of Team and Team has collection of Player. You need to be careful about integrity in add/remove operations, because they are not "atomic"

Upvotes: 2

Related Questions