面向对象编程中的多对多关系

10

如何更好地建模多对多关系?

假设我们有两个类,Team(团队)Player(球员)

  • 任何一个Player(球员)都可以在多个Team(团队)
  • 任何Team(团队)都可以有尽可能多的Player(球员)

我喜欢调用以下方法:

  • playerX.getTeamList() 获取他/她所在的所有Team(团队)的列表
  • teamY.getPlayerList() 获取该Team(团队)中的所有Player(球员)的列表

(或者以其他有效的方式实现)

我能想到两种方法来实现这一点,但它们并不像良好的oop设计模式。

您能否想到任何好的方法,例如设计模式?

7个回答

6

玩家和团队之间的关系形成了二分图。 期待评论(和反对票?)!我是一个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的函数式编程。我不确定二分图甚至是否是一种设计模式。 - frezq

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

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

很合理。

3
你忽略了真正的问题,即需要保持内容同步。为了确保这一点,一种方法是将其中一个实现为另一个的方式。 - reinierpost
@rein 谁说那是“真正的问题”?除非我们知道他的应用程序是如何编写的,否则我们无法确定任何问题。他没有指定它们是模型(逻辑无关的无人机,装满数据并发送)还是实体(具有支持惰性加载和其他存储范例的丰富框架的类),或者其他什么东西。这些类型的最简单模型是由存储库或某种存储层实例化的,该存储库或存储层负责影响团队和球员的所有操作。 - user1228

3

将多对多关系拆分为两个一对多关系。这样做可以使一切变得更加简单。


2

没问题,Player 有一个 Team 集合,而 Team 则有一个 Player 集合。在添加或删除操作时需要注意完整性,因为它们不是“原子性”的。


2
值得区分 API 的感觉和实际实现。虽然两个类都可以公开这样的集合(例如 get*List()),但它们不一定必须持有集合实例。
我建议您创建一个名为 League 的类或类似的东西,它保存某种私有玩家-团队映射字典。通过 Team/Player 实例对这些“集合”的添加应调用 League 实例上的内部方法来更新映射。这样,您可以保持更新具有原子性(如 Andrey 建议的那样)且没有错误。

1

Will的回答是正确的。然而,为了处理同步问题,我可能会从ObservableCollection开始。让关系的一侧成为“主控方”,跟踪另一侧的添加/移除并处理同步。

然而,请注意,如果一个对象正在订阅另一个对象上的事件,那么这是一个强引用,将阻止垃圾回收。最有可能的情况是它们同时离开范围,因此这不是问题,但需要注意。


嗯...我们在哪里见过这个问题 :) - LBushkin

0

在我看来,你所描述的是面向对象编程的“自然”方式。XXX.getXXXList() 是你的类的接口。对于数量有限的类,这是正确的方法。

考虑到有1000个可以“互相连接”的类。那么使用一些ManyToManyManager可能会很有趣,可以将一个对象放入其中,将另一个对象添加到与一个对象相关联的对象中,并检索与另一个对象相关的所有对象的列表。这将是一种委托与实现的方式。

当然,如果你将你的多对多关系委托给另一个实例,你的对象模型就不再反映出那种多对多关系了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接