Reputation: 19
To build a dynamic football league table generator. A league table for football. Each team plays a number of matches and the results of each match build the table.
Any suggestion to avoid the if-else statement?
matches.stream().forEach(match -> {
// Find the record of home team and away team in the league table
homeTeamRecord = tableEntries.stream().filter(t -> t.getTeamName().equals(match.getHomeTeam())).findFirst().get();
awayTeamRecord = tableEntries.stream().filter(t -> t.getTeamName().equals(match.getAwayTeam())).findFirst().get();
/*If home team score > away team score, then
* home team + 3 points
* home team's wins + 1
* away team's lost + 1
*/
if (match.getHomeScore() > match.getAwayScore()) {
homeTeamRecord.setPoints(homeTeamRecord.getPoints() + 3);
homeTeamRecord.setWon(homeTeamRecord.getWon() + 1);
awayTeamRecord.setLost(awayTeamRecord.getLost() + 1);
/*If home team score < away team score, then
* away team + 3 points
* away team's wins + 1
* home team's lost + 1
*/
} else if (match.getHomeScore() < match.getAwayScore()) {
awayTeamRecord.setPoints(awayTeamRecord.getPoints() + 3);
awayTeamRecord.setWon(awayTeamRecord.getWon() + 1);
homeTeamRecord.setLost(homeTeamRecord.getLost() + 1);
/*If home team score equals to away team score, then
* home team + 1 point
* away team + 1 point
* home team's draws + 1
* away team's draws + 1
*/
} else if (match.getHomeScore() == match.getAwayScore()) {
homeTeamRecord.setPoints(homeTeamRecord.getPoints() + 1);
awayTeamRecord.setPoints(awayTeamRecord.getPoints() + 1);
homeTeamRecord.setDrawn(homeTeamRecord.getDrawn() + 1);
awayTeamRecord.setDrawn(awayTeamRecord.getDrawn() + 1);
}
// Calculate 'played', 'goals for', 'goals against', 'goal difference' of home team and away team according to their latest match result
homeTeamRecord.setPlayed(homeTeamRecord.getPlayed() + 1);
awayTeamRecord.setPlayed(awayTeamRecord.getPlayed() + 1);
homeTeamRecord.setGoalsFor(homeTeamRecord.getGoalsFor() + match.getHomeScore());
awayTeamRecord.setGoalsFor(awayTeamRecord.getGoalsFor() + match.getAwayScore());
homeTeamRecord.setGoalsAgainst(homeTeamRecord.getGoalsAgainst() + match.getAwayScore());
awayTeamRecord.setGoalsAgainst(awayTeamRecord.getGoalsAgainst() + match.getHomeScore());
homeTeamRecord.setGoalDifference(homeTeamRecord.getGoalDifference() + match.getHomeScore() - match.getAwayScore());
awayTeamRecord.setGoalDifference(awayTeamRecord.getGoalDifference() + match.getAwayScore() - match.getHomeScore());
// Update the league table with the latest team record
tableEntries.set(tableEntries.indexOf(homeTeamRecord), homeTeamRecord);
tableEntries.set(tableEntries.indexOf(awayTeamRecord), awayTeamRecord);
});
Upvotes: 1
Views: 111
Reputation: 61986
I would concur with davidxxx that the if
statement is better than any alternative in this particular case. But if you really must do this, or if you want to see how you would do it for the sake of the exercise, you can try the following:
int d = Integer.signum(match.getHomeScore() - match.getAwayScore());
This will yield 1
if the home team won, 0 if it was a draw, and -1
if the away team won. (Regardless of how big the difference was in the actual scores.)
Then consider this:
int[] pointTable = { 0, 1, 3 };
int points = pointTable[d + 1];
This will yield 0
, 1
, or 3
depending on whether there was an away-win, a draw, or a home-win.
(There may even be some way of calculating points
from d
which involves only math functions and no table lookup, but I doubt that it will be easier to understand by looking at it.)
So, once you have d
and points
all you need to do is add or subtract d
and points
from every single one of the fields shown in your question. No if
statements necessary.
The actual implementation of this idea is left as an exercise to the reader.
(We are here to help, we are not here to do your homework for you.)
(Also: the word 'code' in the sense of "program code" is uncountable. There is no such thing as "codes".)
Upvotes: 1
Reputation: 131346
Long story short : keep your conditional statements.
We generally advise you to refactor them into subclasses as these represent different abstractions but you are not in this case.
And as alternative to subclassing, defining them in a Map<Predicate<Match, BiConsumer<Team,Team>>
is not necessarily best.
Here you have 3 cases to check :
To determinate the actual case you need to compare computed results from the two teams.
Conditional statements appears as a right approach to perform the task.
Suppose you introduce an abstraction to get rid of chained conditional statements such as a ResultRule
interface with a boolean applyRule(Match match, Team homeTeamRecord, Team awayTeamRecord)
method and move logic of each case as 3 subclasses of ResultRule
.
For example HomeWinRule
would look like :
public HomeWinRule implements ResultRule{
public boolean applyRule(Match match, Team homeTeamRecord, Team awayTeamRecord){
if (match.getHomeScore() > match.getAwayScore()) {
homeTeamRecord.setPoints(homeTeamRecord.getPoints() + 3);
homeTeamRecord.setWon(homeTeamRecord.getWon() + 1);
awayTeamRecord.setLost(awayTeamRecord.getLost() + 1);
return true;
}
return false;
}
Is it better ?
Introducing this class and these subclasses don't bring great value since functionally cases are bounded : win/lose/equality. You will probably not add or remove new cases and the logic inside the cases is simple enough. Besides, the conditional statement will not disappear but move into the subclass as you can notice since here you don't rely on polymorphism but on a series of rule check/apply.
This kind of pattern makes sense when rules can be added/removed/modified often and so you want to isolate them.
Upvotes: 1