类设计问题:列表联合和所有统计数据
我有一个 Player 类和一个 Stat 类。 Player 类有一个 List 属性,其中 PlayerStat 有一个 List 和 XP 属性。我认为我的设计有缺陷,因为我在做我认为应该很容易的事情时遇到了困难。我想列出所有玩家及其所有统计数据的 XP。下面是这些类和 GetCompletePlayerStats 方法的更多详细信息,这是我真正不喜欢的。我基本上需要列出玩家所有统计数据的 XP,如果玩家没有统计数据,那么它的 XP 应该为零。任何设计帮助/建议将不胜感激。
public class Stat : EntityBase{
public virtual string Name { get; set; }
public virtual UnitOfMeasure Unit { get; set; }
public virtual int UnitXP { get; set; }
}
public class Player : EntityBase{
public virtual string Name { get; set; }
public virtual IList<PlayerStat> PlayerStats { get; set; }
public virtual List<PlayerStat> GetCompletePlayerStats(IQueryable<Stat> stats)
{
var allStats = new List<PlayerStat>();
var playerStatIds = PlayerStats.Select(ps => ps.PlayerStatistic.Id).ToList();
if (playerStatIds.Count == 0)
{
allStats.AddRange(stats.Select(stat => new PlayerStat() {PlayerStatistic = stat, XP = 0}));
}
else
{
var zeroStats = stats.Where(s => !playerStatIds.Contains(s.Id)).ToList();
allStats.AddRange(zeroStats.Select(zeroStat => new PlayerStat() {PlayerStatistic = zeroStat, XP = 0}));
allStats.AddRange(PlayerStats);
}
return allStats;
}
}
public class PlayerStat : EntityBase{
public virtual Stat PlayerStatistic { get; set; }
public virtual double XP { get; set; }
}
I have a Player class and a Stat class. The Player class has a List property where PlayerStat has a List and XP properties. I think my design is flawed because I am having trouble doing things that I think should be easy. I want to list out all Players and their XP for all Stats. Below are more details of the classes and the GetCompletePlayerStats method which is what I really don't like. I basically need to list out the XP for all stats for a Player, if the player doesn't have a stat then it should have an XP of zero. Any design help/suggestions would be appreciated.
public class Stat : EntityBase{
public virtual string Name { get; set; }
public virtual UnitOfMeasure Unit { get; set; }
public virtual int UnitXP { get; set; }
}
public class Player : EntityBase{
public virtual string Name { get; set; }
public virtual IList<PlayerStat> PlayerStats { get; set; }
public virtual List<PlayerStat> GetCompletePlayerStats(IQueryable<Stat> stats)
{
var allStats = new List<PlayerStat>();
var playerStatIds = PlayerStats.Select(ps => ps.PlayerStatistic.Id).ToList();
if (playerStatIds.Count == 0)
{
allStats.AddRange(stats.Select(stat => new PlayerStat() {PlayerStatistic = stat, XP = 0}));
}
else
{
var zeroStats = stats.Where(s => !playerStatIds.Contains(s.Id)).ToList();
allStats.AddRange(zeroStats.Select(zeroStat => new PlayerStat() {PlayerStatistic = zeroStat, XP = 0}));
allStats.AddRange(PlayerStats);
}
return allStats;
}
}
public class PlayerStat : EntityBase{
public virtual Stat PlayerStatistic { get; set; }
public virtual double XP { get; set; }
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我必须承认,到目前为止,我并没有真正看到你们的班级设计有什么重大缺陷。当然,我对大局以及游戏的设计方式没有任何见解,因为这只是其中的一小部分。
但是,您说您并不真正喜欢它是
GetCompletePlayerStats
。我必须读几遍才能理解你在这里想做什么。如果我没看错的话,您只想返回与每个给定Stat
对象相对应的PlayerStat
对象。我猜Stat
有一个Id
字段(您在方法中使用它)来比较其中两个字段的语义相等性。鉴于到目前为止我做出了正确的假设(不幸的是,您没有提供太多信息),该方法可以简化为:
这里的方法不需要
IQueryable
而是需要IEnumerable
通过一个foreach
循环进行迭代,并生成相应的PlayerStats
对象(如果有的话),或者创建一个新的,否则将 XP 设置为 0(空合并运算符??
在这些情况下非常有用)。希望有帮助!
I have to admit, I dont really see a major drawback in your class design so far. Of course I dont have any insight in the greater picture and how your game is designed, since this is only a little section of it.
However, you said it is the
GetCompletePlayerStats
that you dont really like. I had to read it several times to understand what you are trying to do here. If I saw that right, you just want to return aPlayerStat
object corresponding to each givenStat
object. I guessStat
has anId
field (you are using it in your method) to compare two of them for semantic equality.Given, that I made the right assumptions so far (unfortunately, you didnt provide much info), the method can be simplified to something like:
This method here doesnt require a
IQueryable
but rather aIEnumerable
to iterate over via aforeach
loop, and yield out the correspondingPlayerStats
object if there is one, or create a new one with XP set to 0 otherwise (The null-coalescing operator??
is very useful in those cases).Hope that helps!
使用现有的设计,可以这样简化此方法:
请注意,由于这实际上是一个外连接操作(您将
stats
与PlayerStats
连接,但您还需要不匹配的结果为零)您也可以使用 LINQ 的 GroupJoin() 操作来完成此操作,尽管我怀疑这会降低可读性。你的设计让我困扰的是名称的模糊性,例如你同时拥有 PlayerStat 类和 PlayerStatistic 属性,它们的含义略有不同;考虑以不同的方式命名事物,事情可能看起来更好;事实上,对于任何情况,这可能是我能给你的最好的设计建议:)
With the existing design, this method can be simplified thus:
Note that since this is effectively an outer-join operation (you're joining
stats
withPlayerStats
but you also need the non-matches to yield as zero) you can also do it with LINQ's GroupJoin() operation, although I suspect that would be much less readable.What does bother me about your design is the ambiguity of names, for example you have both the
PlayerStat
class and thePlayerStatistic
property and they mean subtly different things; consider naming things differently and things might look better; in fact that's probably the best design advice I can give you, for any situation :)