Phils quick-n-dirty intro to object-oriented thinking #4

Object planning

Okay, let's put some of this stuff in action! But before we act, we need a plan.

The game plan

Let's say you wanted to write a small poker game. We'll assume fairly basic rules. The first thing you may start wondering is: what should my objects be?

As mentioned in #3, it's a good thing when you have some physical objects to deal with, because they usually map fairly well to software objects. In this case, the obvious physical objects are:

 Players
 Cards
 Deck
Those cover the absolute minimum of things you need to play poker. You might go further, and think of
 Hand ("Poker hand")
 Table

I think that pretty much covers all the basic object types we'll need. Now, depending on just how object-crazy you are, you may want to narrow down some of these objects. Let's look at some of the drawbacks to the above objects

Card

-- Unless you're planning to do some pretty fancy stuff with cards, (for example, graphical animated cards) this is a pretty simplistic data element. You could probably just say "Well, there are 52 unique cards in a deck.. I can just represent them as an int. 1-13 would be Ace-of-hearts,2-of-hearts,...King-of-hearts. 14-26 would be Ace-of-spades, 2-of-spaces, ...King-of-spades, etc"

It really depends on your overall game handling. If you know you're only going to look at cards in one, maybe two functions, then you could use the int representation. On the other hand, if you are going to be looking at card values all over the place, it makes things much cleaner to have a Card class, with easy-to-read methods like Card.getSuit() and Card.getValue()

Table

-- This is a potentially nice object to keep things neat and tidy. It makes especial sense to have a table object, if you have some sort of graphical display. In that case, a "Table" object would keep track of the location of "Cards". It keep track of what is showing, in front of whom. It could also keep track of displaying what player is "sitting" where.

On the other hand, if you were writing an extremely simplified poker "back end", then having a Table object would be overkill.

Player/Hand

A "Player" is clearly an object, and a Player usually holds a "Poker hand". This suggests that you may want objects for both of them. However, these are two objects that could potentially be merged into a single object. You never have a player without a hand. You never have a hand without a player. So, if nothing outside of Player interacts with "Hand", you may want to implement any "Hand" concepts entirely inside the Player object itself.

This is where the "high cohesion, loose coupling" from chapter #3 comes in again. If making them a single object, reduces the total number of access functions for you, it's probably a good thing. In other words if

  PlayerObj # of methods =5
  HandObj # of methods =5
but
 PlayerHandObj # of methods =8
you have probably reduced complexity somewhat. But that's just a rough guideline. The bottom-line measure should always be: which seems simpler and neater??

The counterpoint to merging them (you knew there had to be one, right? :-) would be if you were planning on doing interesting things with Players, that had nothing to do with Hands, and Hands were more complex than

  class Hand
  {
    Card[5];
  }

In that case, you have two objects that are linked to each other, but have a fair amount of code in each object with nothing in common. Then, the "neatness factor" comes into play. If there is no reasonable degree of commonality between them in your game, then keep separate Hand and Player objects.

Objects within Objects

The Player/Hand issue brings us to an important issue: How to handle objects "contained" or "held" within other objects?

In real life, a Player holds a Hand. It makes a lot of sense to have our virtual objects act similarly. But does that mean we should start writing things like

 if(Player.Hand.Card1 == x)...
NO!

The above is a strong temptation to those who may be used to programming with "structs". But it makes for bad object programming. The whole point of having objects, is to have that object manage its own data. If you go directly to a player's hand, you're stopping the player from acting like a true object in its own right.

Think of it this way: if you reached across a table to pull a card from someone else's hand, they wouldn't like it! You might even say, they would object to it...

So, the right thing to do is make sure the Player object has an adequate number of externally visible ways to manipulate a Hand, without others needing to go directly to the Hand object themselves.
Functions that immediately spring to mind are:

 Player.numberOfCards();
 Player.showCards();
 Player.takeCard();
 Player.exchangeCards();
Note how these are all things that "players" would be interested in, with a real game of poker.


Previous section: Places for OOP
Next section: Summary of Game-plan (with sample code!)


OOP Table of Contents --- phil@bolthole.com
Part of bolthole.com... Solaris tips ... ksh tutorial ... AWK Programming tutorial