组织类. .最佳实践

本文关键字:最佳 | 更新日期: 2023-09-27 18:18:11

假设我有一个如下的类

    class FootballPlayer
    {
        public string Name { get; set; }
        public string TeamName { get; set; }
        public int CareerGoals { get; set; }
        public int CareerAssists { get; set; }
        public int CareerPasses { get; set; }
        public int SeasonGoals { get; set; }
        public int SeasonAssists { get; set; }
        public int SeasonPasses { get; set; }
        public int CurrentMatchGoals { get; set; }
        public int CurrentMatchAssists { get; set; }
        public int CurrentMatchPasses { get; set; }
    }

但是我想把它组织得更好,所以我该怎么做呢?现在我试着这样做-

    class CareerDetails
    {
        public int Goals;
        public int Assists;
        public int Passes;
    }
    class CurrentMatchDetails
    {
        public int Goals;
        public int Assists;
        public int Passes;
        public bool IsCaptain;
    }
    class GeneralDetails
    {
        public string Name;
        public string TeamName;
    }
    class SeasonDetails
    {
        public int Goals;
        public int Assists;
        public int Passes;
        public int MatchesPlayed;
    }
    class FootballPlayer
    {
        public CurrentMatchDetails CurrentMatchDetails { get; set; }
        public SeasonDetails SeasonDetails { get; set; }
        public CareerDetails CareerDetails { get; set; }
        public GeneralDetails GeneralDetails { get; set; }
    }

我不喜欢这个

  • 我必须使类(SeasonDetails, CareerDetails等)公开
  • 我必须在实例化FootballPlayerClass
  • 之后分别实例化所有这些类

但我不确定这是否是最佳实践。我正在考虑在类FootballPlayer中创建一个嵌入类。

我将在WPF应用程序中使用该类,并将在我的FootballPlayer类上实现INotifyPropertyChanged。通过使用上面的方法,我将不得不在所有类(如CareerDetails等)上实现INPC。那么我应该做什么呢,还是应该坚持我现有的?

我可能有另一个基类名为'FootballTeam',它也可能有一个子类名为CurrentMatchDetails -它可能看起来像这样

    class CurrentMatchDetails
    {
        public double TimeElapsed;
        public string RefereeName;
    }

所以我应该能够访问这样的属性teamObject.CurrentMatchDetails.RefereeName或playerObject.CurrentMatchDetails.Goals;

组织类. .最佳实践

您应该创建一个StatDetails对象:

class FootballPlayer
{
    public FootballPlay()
    {
        CareerStats = new StatDetails();
        SeasonStats = new StatDetails();
        CurrentStats = new StatDetails();
    }
    public string Name { get; set; }
    public string TeamName { get; set; }
    public StatDetails CareerStats { get; set; }
    public StatDetails SeasonStats { get; set; }
    public StatDetails CurrentStats { get; set; }
}
class StatDetails
{
    public int Goals { get; set; }
    public int Assists { get; set; }
    public int Passes { get; set; }
}

通过这种方式,您只需要在两个类上实现INotifyPropertyChanged

我可能有另一个基类名为'FootballTeam',它可以有一个子类名为CurrentMatchDetails

首先,一个名为FootBallTeam的类不应该有一个名为CurrentMatchDetails的子类。继承不是一种代码共享机制,而是根据物理世界进行建模。CurrentMatchDetailsFootballTeam吗?我看不出来。继承适用于这种模型:

class FootballPlayer
{
}
class StarPlayer : FootballPlayer
{
}

这里StarPlayer 是一个 FootballPlayer,所以足球运动员的所有属性也应该在明星球员身上可用。您应该使用组合,请在这里阅读更多:更喜欢组合而不是继承?在你的例子中,FootBallTeam应该是CurrentMatchDetails的一个属性。

我没有比Ed的更好的答案(他+1),我只是试着进一步充实他的。

public class PlayerStat //Add 'Player' to name since stats can be for tourneys too
{
    public int Goals { get; set; }
    public int Assists { get; set; }
    public int Passes { get; set; }
}
public class PlayerCurrentMatchStat : PlayerStat 
{
    public bool IsCaptain { get; set; }
}

public class PlayerSeasonStat : PlayerStat 
{
    public int MatchesPlayed { get; set; }
}
public class PlayerCareerStat : PlayerStat 
{
}

//And your football player goes like this:
class FootballPlayer
{
    public FootballPlay()
    {
        CurrentStats = new CurrentStat();
        SeasonStats = new SeasonStat();
        CareerStats = new CareerStat();
    }
    public string Name { get; set; }
    public string TeamName { get; set; }   
    public PlayerCurrentMatchStat CurrentMatchStat { get; set; }
    public PlayerSeasonStat  SeasonStat { get; set; } //no need of naming 'Player' 
    public PlayerCareerStat CareerStat { get; set; }  //inside Player class
}

如果某些类的可见性困扰您,您可以通过将它们推入某个特定的命名空间来保护它。最后,一支足球队即使没有参加比赛,也仍然是完全有效的实体。这样建模:

class FootballTeam
{
    // all what makes a good unit
}    
class FootballMatch
{
    public FootBallTeam Team1 { get; set; } 
    public FootBallTeam Team2 { get; set; } 
    public double TimeElapsed { get; set; }   
    public string RefereeName { get; set; }   
}

是有意义的。现在把它命名为:

FootballMatch currentMatch = new FootballMatch(...whatever

警告:上面的设计是好的,但仍然有点臭。为什么FootballPlayer会有PlayerCurrentMatchStat ?一个足球运动员即使坐在替补席上,他仍然是一个完美的球员。也许你可以把它设为空,如果他不在匹配中。PlayerSeasonStat也是一样——如果是的话,是哪个季节?我会完全重新设计它,我觉得它有点复杂,但更合乎逻辑。

public interface Stat //common interface which can be for tourneys, matches etc too
{
    int Goals { get; set; }
    int Assists { get; set; }
    int Passes { get; set; }
}
//You might want to break this interface further to fit in other specific stats
//like player stat, match stat etc.
//Also making it an interface rather than base class is better, you shouldnt have 
//2 different entities like PlayerStat and MatchStat share a common base class
public class PlayerStat : Stat //can be career stat, single match stat etc;
{                              //depends on context where you call it
    public int Goals { get; set; }
    public int Assists { get; set; }
    public int Passes { get; set; }
}
//another example
public class MatchStat : Stat 
{
    public int Goals { get; set; }
    public int Assists { get; set; }
    public int Passes { get; set; }
    public int Viewership { get; set; }
}

class Team
{
    // all what makes a good unit
}    
class Match
{
    public Team Team1 { get; set; } 
    public Team Team2 { get; set; } 
    public double TimeElapsed { get; set; }   
    public string RefereeName { get; set; } 
    public MatchStat Stat { get; set; } //a match has match stat
}

//provide a suitable constructor that takes a player and a match
public class PlayerMatchStat
{
    public Player Player { get; set; }
    public Match Match { get; set; }
    public PlayerStat Stat { get; set; } //should return player's stat for this match
    public bool IsCaptain { get; set; }
    public int DistanceCompleted { get; set; }
}
//provide a suitable constructor that takes a player and a season
public class PlayerSeasonStat
{   
    public bool Player { get; set; }
    public Season Season { get; set; } //have a season class
    public PlayerStat Stat { get; set; } //should return player's stat for this season
    public int RedCards { get; set; }
}

//and lastly
class Player
{
    public Player()
    {
        //init work
    }
    public string Name { get; set; } 
    public PlayerStat CareerStat { get; set; } //just like match has match stat
    public Team[] Teams { get; set; } //Team name shouldn't go within a player 
                                      //class, he could be in many teams.
    //since player inherently has no match or season, we shall provide methods to query them
    public PlayerMatchStat GetMatchStat(Match match)
    {
        return new PlayerMatchStat(match, this);
    }
    public PlayerSeasonStat GetSeasonStat(Season season)
    {
        return new PlayerSeasonStat(season, this);
    }
}

在这里,继承很少被使用(在需要继承的地方),使用的效果很好的是组合。