1

I'm trying to make a sports stats app in Java/Android + Realm.

I have the following classes:

Season 
Player
Matches

I would like the Season to contain a "list" of all the players that played that season and Players to have a "list" of matches.

I currently have actual lists as attributes to each class. For example the Player class:

public class Player{
    String name;
    Int wins;
    Int losses;
    List <Matches> matches;
}

Where I would just use the .add function to add to new matches to the player. Also I did take off some syntax related to Realm for simplicity, but this would be a RealmObject.

Is there a better way to do this? I noticed issues with this implementation, like if I wanted to get all the Matches associated with the season. I would have to go through each player, and account for duplicates. Similarly if I wanted to view all players regardless of Season.

What would the better way be?

Edit: to clarify this is with combat sports, and I'm looking for ways to associate objects with other objects. The real purpose of the app is on a small level, for coaches to keep track of their players. A player is a team essentially. The user is pretty much focused on player stats. Here's the layout with UFC as example.

The app would open to a list of years. From the list let's say I select 2019. It would then open up a list of all players in 2019 that had matches. I select Khabib. It would then show me his stats and matches for that year (with the option to change date so I can change to view for past 3 years or life time if needed). And then I can select a specific match and view it's details.

The issue with my current implementation is modifying ranges. For example, if the user wants to view all players regardless of season, change the range in which matches would be view etc.

  • Even though I posted a rather lengthy answer (for some reason I always like sports game architecture questions), but this is far too broad and opinion-based to give you a single authoritative answer, which is probably why this question has so many down-votes at this point (-3). – Greg Burghardt May 11 at 14:57
  • 1
    This raises an interesting question about implementing associations between entities (season, matches, players) considering unique identity of entities (two players may share the same match) which seems not opinion based, despite the subjective wording (“best”, “better”). – Christophe May 11 at 15:08
  • @GregBurghardt I guess it does seem opinion based, I just feel like the way I did it with lists within lists is just outright bad. So was looking for suggestions with better ways. – musicalears May 12 at 2:05
6

It feels like a good number of things are missing, to be honest.

  • A Team has many Players.
  • A Match is played between two Teams.
  • A Season is composed of many Matches.
  • A Season is managed by a SportsAssociation (think: National Basketball League [USA], FIFA, etc...)
  • A SportsAssociation compiles a Team's SeasonRecord
    • A SeasonRecord references a Team and a list of Matches the Team has played. It can also have methods that compile statistics, and is likely a "read-only" model

Just to give you some things to think about. There are even more entities that you can tease out from this structure. Some will be read-write entities, like SportsAssociation, Match or Team. Some will basically be wrappers for queries, like SeasonRecord.

The one thing I do know about your proposed design is that a single Team does not own a Match. A Match is its own entity that references two different Teams and contains a score, and quite possibly a date. If you want some stats for a specific Team then a TeamRecord would be useful, because it could reference a Team and have a collection of Matches. The TeamRecord class would also be read-only, and expose public methods for calculating statistics.

Just a few lines of code as food for thought:

nba = new SportsAssociation("National Basketball League", "NBA");

rival1 = new Team("Detroit Pistons");
rival1.addPlayerToRoster(new Player(...));
rival1.addPlayerToRoster(new Player(...));
...

rival2 = new Team("Chicago Bulls");
rival2.addPlayerToRoster(new Player(...));
rival2.addPlayerToRoster(new Player(...));
...

nba.addTeam(rival1);
nba.addTeam(rival2);

season = nba.createSeason("2020-2021", beginDate, endDate);
match = season.getMatch(1);
// .. play match

seasonRecord = season.getSeasonRecord(rival1);
teamRecord = season.getTeamRecord(rival1);
seasonLeader = seasonRecord.getLeader(); // Returns rival1 of course ;-)
| improve this answer | |
  • Sounds like an expert who already wrote such application ten times for all kind of sport associations 😉 – Christophe May 11 at 14:58
  • I just hope there aren't any Bulls fans on this site, otherwise I'll be down-voted into oblivion ;-) – Greg Burghardt May 11 at 15:01
  • Love how you say so much with such little code. – candied_orange May 11 at 15:30
  • I should've clarified this earlier, but there would be no team for this specific app. I'm working with combat sports. So it is 1 on 1. A player is a team. Regardless, this was definitely some help! – musicalears May 12 at 2:03
  • @musicalears: a team is a player until your users want a multiplayer mode with teams. That is such a common feature in games, especially in our interconnected, social networked world that having a team entity in your architecture is probably just part of the minimal amount of complexity required in this problem space. – Greg Burghardt May 12 at 2:28
2

Expanding on Greg Burghardt amazing answer with a visual aid (and loosely using College Football as an example):

enter image description here

public class Association {

    List<Conference> conferences;
}
public class Conference {

    List<Team> teams;
    List<Season> pastSeasons;
    Season currentSeason;
}

public class Season {

    List<Match> matches;
    TeamRankings teamRankings;
    PlayerRankings playerRankings;
}

public class Team {
    List<Player> roster;
}

public class Match {

    Team team1;
    Team team2;
    Result result;
}
public class Result extends Record {
}
public class Player {
}

public abstract class Record {
}
public class PlayerRankings extends Record {
}

public class TeamRankings extends Record {
}

| improve this answer | |
  • 2
    Maybe I'm being pedantic here but you've shown all these relationships as compositions (closed diamonds.) I would argue that the players existence is separate from being a member of a team e.g a Player could be associated with different teams at different times or even at the same time e.g. a club team and a World Cup or Olympic national team. – JimmyJames May 14 at 16:54
  • I really like this implementation for football, with what was said above about players being separate from teams. The visual aid is nice too! – musicalears May 15 at 11:09
1

What you are doing, is trying to describe the "domain" sort-of independently first. Trying to figure out what contains what, what has what data elements inside, etc.

You are wondering whether this model is "good" according to some metric, I guess.

Then you mention as an "edit", as an afterthought what this will be used for.

Modeling goes exactly the opposite way. There is no "objective" (excuse the pun) model to anything. Objects don't reflect the "reality", at least not this way. You have to model your requirements. There is no model without requirements.

Let me demonstrate. If you say:

The app would open to a list of years.

I would say:

interface Years {
   fun list(): View
}

Then you say:

From the list let's say I select 2019. It would then open up a list of all players in 2019 that had matches.

Ok, here we go:

interface Year {
   fun listPlayers(): View
} 

Now there are some technical reasons why you can't really return "View", but the example here is for the modeling part. You start with the requirements, you try to write down what needs to be there. Everything else, like what instance variables, data, etc. is completely secondary, not really important from an object-oriented standpoint.

I am aware, as should you, that this is not how people do it, and android applications are not written this way because reasons. But this is what object-orientation, and an appropriate, long-term maintainable design for your requirements would look like.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.