6

Tennis is played as singles or doubles. I considered making my tennis scoring model logic refer to "teams" throughout its naming since "player" wouldn't take into account doubles. However, seeing teamOne and teamTwo throughout the code to accommodate both modes seems awkward since a team of one person doesn't make sense and the sport is usually played as singles.

What would be a good way to reconcile this? I try to adhere to the Swift API Design Guidelines since it's the language I'm using. Maybe I'm bikeshedding and I should just go with teamOne and teamTwo even if it's imprecise?

  • Nobody can really make this decision for you. You could have two distinct models, or use "team" or "party" as a catch-all term if you have a single one. Your choice of names may be informed by how you actually modeled things. You should also try researching tennis terminology, maybe they already have a convenient term. – Filip Milovanović Jan 3 '20 at 10:10
  • 1
    just checked out some tennis score sheets and "team" is used fairly often – Ewan Jan 3 '20 at 10:14
  • 1
    If you consider that teams and players are, essentially, at the same level of abstraction, you could provide a higher level, as for instance, contenders. A way to refer the ppl who did participate in a match or championship regardless of their number. Anyways I think "doubles" is a "modality" of the game|match or the championship, So it would be a property of the Match or a "sort" of Match – Laiv Jan 3 '20 at 12:48
  • 3
    Both "player" and "team" could be misleading. British English also uses "side" to preserve this ambiguity – Kilian Foth Jan 3 '20 at 13:49
  • 3
    An individual is a team of one. – Robert Harvey Jan 3 '20 at 18:41
6

A player is a player, regardless of how many of them make up a team. A team is a team if there is more than one player per side. You could go with "Side" as a name, but I think you are missing an abstraction here. The scoring for singles or doubles is the same, but slight variations exist in the game play, and the number of players per side. This translates to differences in both logic and data. Sounds like a great case for inheritance.

You need a TennisMatch abstract parent class and two concrete sub classes: SinglesMatch and DoublesMatch.

This gives you the split required to name things as they are. The SinglesMatch has two sides, but only one player per side. The DoublesMatch also has two sides composed of two players each.

Now that we have properly identified the abstractions — this is the key — you can give things proper names:

  • Player
  • Score
  • TennisMatch
  • TennisMatch has a Score
  • SinglesMatch is a TennisMatch
  • SinglesMatch has 2 Players on 2 sides
  • DoublesMatch is a TennisMatch
  • DoublesMatch has 4 Players on 2 sides
  • It's worth noting that my Match type is a structure rather than a class (docs.swift.org/swift-book/LanguageGuide/…), so I'm unable to add inheritance. I had not anticipated this case for subclassing. – Austin Conlon Mar 4 '20 at 12:05
  • @AustinConlon: I would question why Match needs to be a struct. Especially since structs are passed by value rather than by reference. Was there a particular advantage to making Match a struct? – Greg Burghardt Mar 4 '20 at 12:54
  • I made it a structure value type so that I could push and pop the Match onto an undo stack. Since the primary client is an Apple Watch, it's important that there be an undo button if the user accidentally taps the wrong button. – Austin Conlon Mar 5 '20 at 0:07
  • I'm not seeing how a struct works better than an immutable class. I've never developed something for an Apple Watch before, though, so my ignorance of that platform and its design patterns might be showing through. – Greg Burghardt Mar 5 '20 at 0:25
  • C has inheritance. It is user imposed using structs. So there is no technical limitation here. What you need to do is take a trick often used in BTree design. Both implementations have the same binary size. they both have a tag field somehwere (usually in a pointer), but in the struct is not an issue. Create a base struct which has the correct size, all common fields and a padding member/s. Create two implementation structs with the exact same common fields, and their special fields in the padding of the base struct. Cast the struct to the other structs as required. – Kain0_0 Sep 15 '20 at 1:00
2

First of all, I'd strongly suggest to avoid xxxOne and xxxTwo: use an array instead. This makes it easier to work with the right player without a lot of error-prone conditionals:

var players = [Player](); 
...
for player in players {    // for-in loop 
   player.doSomething(); 
}
player[1];                 // access to a specific player

Now to the naming itself. If you see player more as an individual, and if you do not really agree that a team could be made of one persone, you could perhaps chose a more neutral term like participant. Participant could have one or several members.

This does not exclude to subclass the Participant class and let Player and Team inherit from it if some more specific behavior or properties are needed. On the other side (but I don't think it's the case here), if you do not see much commonality, you could also see Participant as a protocol that is then implemented by Player and Team.

0

Normally my suggestion would be to check the official rules, as those are what you will in effect be codifying. However, in the case of tennis, doubles seems to be treated as a bit of an afterthought. "Player" is used generally and where doubles is in context the phase "Player or Team" is used.

Depending on what exactly you are writing, I would be tempted to completely separate the two games classes into namespaces ie.

Tennis.Singles.Player

and

Tennis.Doubles.Team
Tennis.Doubles.Player

etc

I don't fully understand the rules of tennis, so I would be wary of obscure tournament rules which might prevent reuse of classes between the two versions of the game.

0

I would use "Part" o "Party" for each of the two adversaries playing a match. I would then subclass it into "Player" and "Team", with "Team" having a whole/part relationship with cardinality 2 towards "Player".

This neatly captures the following facts:

  • A match is played by two parties.
  • A party may be an individual player or a team.
  • A team is always composed of 2 players.

There is an additional fact that you would need to enforce through business logic, as it's harder to capture in the static model: the fact that the two parties in a match are of the same subtype, either two players or two teams, that is there can't be a match between an individual player and a team. You could implement this by having a "Match" class with 2 subtypes, "IndividualsMatch" and "TeamsMatch", but this is a bit cumbersome as you would need to maintain two sets of associations between subtypes.

0

I would model it in the following way.

  • A Match has opponents.

  • Oponent can be a team of players, or a player, or any number of players.

  • The match has outcome

  • An opponent can score.

  • Player may score as long as a player is an opponent. A player as part of a team does not score alone. So scoring does not makes sense in the context of team play.

  • Now this kind of abstract thinking will allow you to model any type of competing event not just tennis.

If we express this via JSON it would look like that:

{
   match : {
      oponents : [ {
           oponenName : "Team Blue"
           players : [
               {
                   name: "Player 1"
               },
               {
                   name: "Player 2"
               }
               ]
           }
      },
    {
       oponentName : "Team Red",
       players : [{
       .........................
       }]
       
    }  
    ]
    outcome : {
        ...........
    }
   }
}

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.