oop中的多对多关系

时间:2010-05-06 12:20:48

标签: design-patterns oop

建立多对多关系的最佳方式是什么?

假设我们有两个类,团队播放器

  • 任何播放器可以在多个团队
  • 任何团队可以拥有他们喜欢的播放器

我喜欢称呼

之类的方法
  • playerX.getTeamList()获取他/她所在的所有团队的列表
  • teamY.getPlayerList()获取团队中所有玩家的列表

(或者有其他方式有效地做到这一点)

我可以想到两种方法,但他们感觉不像是一个好的oop pattens。 你能想到任何好的方法,也许是设计模式吗?

7 个答案:

答案 0 :(得分:6)

球员和球队之间的关系来自Bipartite Graph。 期待评论(和downvotes?)!我是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 :(得分:3)

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

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

完全合理。

答案 2 :(得分:2)

没关系,Player的集合TeamTeam集合Player。在添加/删除操作中需要注意完整性,因为它们不是“原子”

答案 3 :(得分:2)

将API感觉与实际实现区分开来是值得的。

虽然两个类都有义务公开这样的集合(例如get * List()),但它们不一定必须保存集合的实例。

我建议您创建一个League类或类似的东西,它包含某种私有玩家团队映射字典。通过Team / Player实例添加到那些“集合”,应调用League实例上的内部方法来更新映射。这样,你保持更新原子(如安德烈建议)和无错误。

答案 4 :(得分:2)

将多对多关系分成两个一对多的关系。使一切变得更加简单。

答案 5 :(得分:1)

Will的回答是正确的。但是,为了处理同步,我可能会从ObservableCollection开始。让关系的一方成为“主人”,在另一方跟踪添加/删除并处理同步。

但是,请注意,如果一个对象在另一个上订阅事件,则这是一个强大的引用,可以防止垃圾回收。他们很可能会同时离开范围,所以这不是问题,但需要注意的是。

答案 6 :(得分:0)

恕我直言,你所描述的是OO的“自然”方式。您的XXX.getXXXList()是您的类的接口。对于限制数量的类,这将是正确的方法。

考虑有1000个类可以“互连”。让一些ManyToManyManager放入一个对象,将另一个对象添加到一个对象的相关对象并检索与另一个对象相关的所有对象的列表可能会很有趣。这将是某种授权与实施。

如果您将多对多委托给另一个实例,那么您的对象模型不再反映多对多关系。