3

Say I have a class as follows

    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; }
    }

But I want to organize it better, so how can I do it. At the moment i tried something like this -

    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; }
    }

A few things I do not like about this

  • I have to make the classes (the SeasonDetails, CareerDetails etc) public
  • I have to instantiate all of these classes separately after instantiating the FootballPlayerClass

But I am not sure if it is the best practice. I was thinking of creating a embedded class within the class FootballPlayer.

I am going to be using the class in a WPF application and going to implement INotifyPropertyChanged on my FootballPlayer class. By using the method above, I am going to have to imlpement INPC on all of the classes such as CareerDetails etc. So what should I do instead or should I stick with what I have?

I may have another base class called 'FootballTeam' which could have a sub-class named CurrentMatchDetails as well - It may look like this

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

so I should be able to access properties like this teamObject.CurrentMatchDetails.RefereeName or playerObject.CurrentMatchDetails.Goals;

Joe Slater
  • 2,483
  • 6
  • 32
  • 49
  • You can make them private, and let FootballPlayer manage them. Make them also static. You can create a `Create` method to initilize all of it. – AAlferez Jun 13 '13 at 18:25
  • 1
    welcome to hell.. we've been waiting for your arrival. You will not believe this, but this problem is just the 1st out of many to follow. I advise you to either make your model in EF and brake the perfect order of layered architecture or you can join me in this pool of fire, there is always room for one more :) – G.Y Jun 13 '13 at 21:24
  • @G.Y wow thanks. Entity Framework may exactly be what I need. Now it is just to understand it through tutorials. Lets see if my small brain can handle another new concept. – Joe Slater Jun 14 '13 at 07:09

2 Answers2

8

You should create a StatDetails object:

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; }
}

In this way, you only have to implement INotifyPropertyChanged on two classes.

Ed Chapel
  • 6,842
  • 3
  • 30
  • 44
  • 1
    FWIW, the fields in the `StatsDetails` will not work with `INotifyPropertyChanged` or WPF in general, the OP will need proper properties. – CodingGorilla Jun 13 '13 at 18:27
  • This was just an example but the CareerDetails may have properties that other classes dont, in which case this does not work. – Joe Slater Jun 13 '13 at 18:28
  • Another thing to consider with this approach is what your bindings will look like. You will need to bind to the sub-properties, ie. `Text={Binding Path=CareerStats.Goals, Mode=TwoWay}`. That may or may not be a problem for you, but it's worth thinking about – CodingGorilla Jun 13 '13 at 18:29
  • @AnkurSharma I think the point here is to follow the http://en.wikipedia.org/wiki/DRY_principle. If you want to subclass the smaller pieces, make bases classes where appropriate and subclass those as necessary. – CodingGorilla Jun 13 '13 at 18:32
  • @AnkurSharma Then it comes down to personal taste. You may have one large object or many smaller objects. With that many differing properties, it's too specific to your solution to have a best practice. Or, "best practice" is to structure it to be consistent within your project, team, or organization. – Ed Chapel Jun 13 '13 at 18:33
  • @CodingGorilla But I really dont like that I have to make the sub-classes public because I will also have a subclass named 'SeasonDetails' for another class called 'FootballTeam'. Thats when it starts getting confusing. – Joe Slater Jun 13 '13 at 18:35
  • @AnkurSharma Unless someone else is using your library (or executable?), IMO the accessibility of the classes inside are not relevant. Who are you wanting to hide those classes from? – CodingGorilla Jun 13 '13 at 18:39
  • @AnkurSharma subclassing is the way to go. Can you add basic structure of 'SeasonDetails' and 'FootballTeam' into your question and show how is it related (no two classes that do different job be named the same. If they does the same then you want only one class anyway)? That would give us more idea. – nawfal Jun 13 '13 at 19:07
  • @AnkurSharma A `FootBallTeam` should never have a subclass named `CurrentMatchDetails` pls.. I will try to make an answer.. But tell me, if visibility is your problem, have you tried nesting classes? – nawfal Jun 13 '13 at 19:33
  • @nawfal plz go ahead and post your answer. I am interested in looking at how nested classes could work. Thanks – Joe Slater Jun 13 '13 at 19:35
  • @AnkurSharma I was wrong, you can't nest them if you're to have properties of their type public. I provided an answer. Nothing much.. – nawfal Jun 13 '13 at 19:54
1

I may have another base class called 'FootballTeam' which could have a sub-class named CurrentMatchDetails as well

First, a class named FootBallTeam should never have a subclass named CurrentMatchDetails. Inheritance is not a code sharing mechanism, but to model according to physical world. Is CurrentMatchDetails a FootballTeam? I see no way. Inheritance work for this kind of model:

class FootballPlayer
{

}

class StarPlayer : FootballPlayer
{

}

Here StarPlayer is a FootballPlayer, so all those properties of a football player should be available on a star player too. You should use composition, please read more here: Prefer composition over inheritance?. In your case FootBallTeam should be a property on the CurrentMatchDetails.

I dont have a better answer than Ed's (+1 for him), I will just try to flesh out his a bit further.

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
}

If visibility of some classes are bothering you, you can protect it by pushing them to some specific namespace. And finally a football team is still perfectly valid entity even if they are not in a match. Model it this way:

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; }   
}

Makes sense. Now call it like:

FootballMatch currentMatch = new FootballMatch(...whatever

Alert: The design above is ok but still a bit smelly. Why would a FootballPlayer have a PlayerCurrentMatchStat? A football player is still a perfect player even if he is in the bench. May be you could make it null if he is not in a match. Same goes for PlayerSeasonStat - if so which season? I would completely redesign it, and imo is a little more complex, but a lot more logical.

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);
    }
}

Here inheritance is used sparingly (where it warrants) and what is used to good effect is composition.

Community
  • 1
  • 1
nawfal
  • 70,104
  • 56
  • 326
  • 368
  • ok i see. I though that sub classes meant like this - mainClass.subClass.property but it is actually related to inheritance. Also in your constructor of FootballPlayer(), should you not instantiate them using ( for e.g. ) new CareerStats() instead of new StatDetails() ? – Joe Slater Jun 13 '13 at 20:00
  • Oh I see, you got the word wrong, oops. You are right on both. Yes subclassing means inheritance. What you meant is composition, and yes I will edit that typo - copy paste mistake :) – nawfal Jun 13 '13 at 20:04
  • @AnkurSharma if all your app is about "Football", then I would suggest you to take off all those `Football` keywords from there, makes your code a lot readable and short. Like `Player`, `Match` etc. If you have `HockeyTeam`s too, then that's a different story :). Btw I think your design can be a bit better. I will update. Catch it. – nawfal Jun 13 '13 at 20:25
  • Thx very much. this is helpful. I agree, I should redesign my code. I will definitely follow your advice. Thx, a better answer than the one below. – Joe Slater Jun 14 '13 at 06:55
  • @AnkurSharma similarly you can have `PlayerTeamStat` (that takes a team and player) and so on. What is important is that you understand the flow (thats why elaborating too much :)) Always think *real world*.. – nawfal Jun 14 '13 at 07:02