【问题标题】:Many-to-many relationship in oopoop中的多对多关系
【发布时间】:2010-05-06 12:20:47
【问题描述】:

建模多对多关系的最佳方法是什么?

假设我们有两个类,TeamPlayer

  • 任何给定的玩家都可以在多个团队
  • 任何团队都可以拥有任意数量的玩家

我喜欢调用类似的方法

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

(或有其他方法可以有效地做到这一点)

我可以想到两种方法来做到这一点,但它们只是感觉不像是好的 oop 模式。 你能想出什么好的方法,也许是设计模式?

【问题讨论】:

    标签: design-patterns oop


    【解决方案1】:

    球员和球队之间的关系形成Bipartite Graph。 期待cmets(和downvotes?)!我是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();
            }
        }
    

    【讨论】:

    • 你得到了你的 -1。这实际上是伪装成 OOP 的函数式编程。我不确定二分图甚至是一种设计模式。
    【解决方案2】:
    public class Player
    {
      public Team[] Teams {get;set;}
    }
    
    public class Team
    {
      public Player[] Players {get;set;}
    }
    

    完全合理。

    【讨论】:

    • 您忽略了真正的问题,即需要保持其内容同步。保证这一点的一种方法是根据另一个实现一个。
    • @rein 谁说这是“真正的问题”?除非我们知道他的申请是如何编写的,否则我们无法判断出什么问题。他没有具体说明它们是模型(充满数据并在途中发送的无逻辑无人机)还是实体(具有支持延迟加载和其他存储范例的丰富框架的类)或其他东西。最简单的模型是这些类型由存储库或某种类型的存储层实例化,该存储层负责影响团队和玩家的所有操作。
    【解决方案3】:

    将多对多关系拆分为两个一对多的关系。让一切变得更加简单。

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

        虽然这两个类都可以公开这样的集合(例如 get*List()),但它们不一定要保存集合的实例。

        我建议你创建一个League 类或类似的东西,它包含某种私人球员-球队映射字典。通过 Team/Player 实例对这些“集合”的添加应该调用 League 实例上的内部方法来更新映射。这样,您可以保持更新的原子性(正如 Andrey 所建议的那样)并且没有错误。

        【讨论】:

          【解决方案6】:

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

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

          【讨论】:

          • 嗯...我们以前在哪里见过这个问题:)
          【解决方案7】:

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

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

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2018-06-15
            • 2011-06-02
            • 2011-02-07
            • 2015-12-30
            • 2020-12-05
            • 2018-09-28
            • 2017-05-22
            • 2013-01-08
            相关资源
            最近更新 更多