cross-platform c++ classes?

Rob Wehrli plug-devel@lists.PLUG.phoenix.az.us
Tue May 22 12:43:01 2001


David Demland wrote:
> 
> Rob,
> 
> Just a few questions. See below.

More comments than questions... :)

> 
> David Demland wrote:
> >
> >
> 
> COMMENTS:
> 
> Why would you need all these extra objects. First of all the Chip and Bet
> are the same object. Chips are just the display unit for the bet. Both of
> which can be handled by a Player. After all is it not the player that makes
> the decision on what the bet is. After all when was the last time you saw a
> video blackjack program exchange Chips instead of just displaying total

I've seen plenty of graphical representations of bet "amounts" often
implemented using "Chips" or other "media," which is also useful for
adding a visual impact including logos, special "chips" and other
graphical elements that have nothing to do with bets or betting. 
Certainly you can make the game as feature-rich or feature-less as
desired, however, by implementing the object as it is in "real life" you
receive the real life "benefits" even if there isn't an immediate need
or representational difference in the way you choose to implement its
functionality.

> numbers? Payout and Table are these not functions of the Dealer? After all

No.  ...and, like so many other things, in some ways of thinking, yes. 
The Dealer is involved with Table and Payout in an obvious relationship
of some sort, however, without a "table" for example, how can your
dealer know the various rules associated with different tables; such as
a $5 minimum or a $500 maximum or some other such "table" specific
"rule."  Assuming that you do not plan to use these "features," by not
coding them, you effectively reduce your implementation to the scope
you've given it.  This makes it harder to implement changes.  And, per
"Pure OOP," what should a dealer really know about a table?  This is a
typical problem with many OO implementations.  People errorneously (no
offense, common error!) say, hey the dealer does this and the dealer
does that so let's put all of this into the dealer.  However, for PURE
OOP, we know that a dealer must interact with some set of rules that are
likely to change in the future...so, let's figure out exactly what a
dealer really does, have the dealer class do JUST that and figure out
where the other relationships exist and implement them so that we really
can have truly *reusable* code.  What happens in your "integrated
dealer" when the table rules change?  You rewrite the dealer?  What code
gets broken as a result?  Payout and Bet are probably interfaces as they
are verbs.  Player uses Bet.  Table uses Payout (not dealer!)...and so
forth.  It is better OOP, but not necessarily easier to implement or
even *needed* for your particular application, however, a correctly
coded dealer would work the same whether he was dealing BJ, Hearts or
Old Maid.  Are you specializing your dealer with blinders on?  (Not
trying to be critical of your choices or thinking, but to offer critical
questions that, if asked, and answered will hopefully shed light on the
design objectives for (my opinion) arguably better OO designs.)

> when playing at a table who controls these decisions? Does the player
> declare who wins, or is it the dealer? The answer to this would show the

Does the dealer *really* declare who wins or is it a set of rules that
the dealer uses to determine it...not that there is an overt difference,
but, you'll recall, it is these seemingly extreme subtleties that make
the difference between a so-so and a "Pure OOP" design.  I think that in
this case, it would be probably a better implementation to allow an
interface used by the dealer to "determine play state" and the dealer's
functions/methods to facilitate the play state actions as required. 
GetNewCardFromDeck(), AssignCardToPlayer(), CollectCardFromPlayer(),
etc.  Let's get "physical" and model the actions of the dealer.  Won't
his decision making process be a function of rules based on the Table
and the Game being played?  Once we have what a Dealer *is*, then we can
subclass for specialization if we choose to do away with the relative
complexities of an interfaces-based implementation of the rules/game
issues.  Of course, in real life, a human dealer is much more than just
a guy/gal who passes out and collects cards and chips.  However, once we
model those physical actions, we have an increasingly more complex
challenge in modeling the decision making process and that is where the
Pure OOP gets broken...IF we try to make the dealer have all of the
facets of a real life dealer.  A good dealer might be able to work any
BJ table in Vegas.  What happens when the rules change slightly, say as
they might in Atlantic City (not that I really know where the rules
vary, but life and code teaches us to build for that eventuality!).  Our
class, in order for the promise of reusability to be preserved, must be
something of the lowest-common denominator or what a dealer is in all
cases.  You'll recall that I suggested a "Participant" (or perhaps a
better name!) to be the collection of
traits/attributes/characteristics/take your pick of what is both a
dealer and a player.  Of course, the rules change between tables, too. 
Maybe your implementation doesn't *need* to consider these facts, but
your design should, if you wish it to be "better" OO.


> real world implementation. Also Shoe is a HASA relationship of deck which
> means that the deck would contain the information for a Shoe object. Since

Huh?  Deck does not have some number of Shoes.  A Shoe has some number
of Decks.  The core question/response validation for a HASA relationship
is who instantiates who?  A Shoe is a container class for holding and
managing decks and providing functions such as shuffling decks.  It is
also code to prevent more than one card from being distributed at a
time.  A shoe may contain several decks and that may be configurable by
a set of Table rules or other criteria.  We do not want to give Deck any
knowledge of Shoe at all.  A well-designed Deck will never know whether
it is being "held" in a Shoe or in a Hand or any other Deck (of Cards)
container and assumedly distribution methods.  Do you see the OO value
here?


> this deals only with the Deck why would anything but the deck need to know
> about this, which brings up the question is Shoe really a separate object or
> part of the Deck?

Obviously Shoe is a separate object and certainly not part of Deck. 
Deck is an autonomous object that Shoe uses and instantiates based on
just how many decks it is designed/desired to have at any given time. 
This is much in the same fashion as Deck would have a HASA relationship
with Card so that a call to:

PlayingCardDeck *pPlayingCardDeck = new PlayingCardDeck();

...would instantiate 52 playing cards of the "face values" that we think
of as Playing Cards.  Obviously, the base class "Deck" would be the same
parent of PinnocleDeck and OldMaidDeck and so forth.  The constructor of
PlayingCardDeck would work its way up to the top of the inheritance
hierarchy then back down giving us the instantiations of "features"
implemented in our "lineage."  Deck could probably be a pure virtual
base.  Now, your use of "specialization" is correct except in the
ultra-extremist/purist's view of dynamic initialization and "late
binding" based implementations that are probably a bit far out of the
scope of your goals for reusability.

> 
> > figured out pretty easy. I'll look at just one of the objects for now the
> > Dealer. The Dealer is a inherited class from Player. This is because the
> > Dealer is nothing more than a super player so to speak.

The wording I think you're looking for is that Dealer is a derived class
from Player.  However, remember my comments on "specialization?"  This
is an often-confused OO design error.  It is so easy to confuse it, that
many people will battle to the death trying to push their belief. 
However, as rationality and "Pure OOP" "dictate," that kind of
"specialization" (super player so to speak) is just plain wrong because
a dealer, as I've tried to point out, is not what a Player IS.  If there
are similarities, find a common base and declare it and subclass your
dealer and player from it.  It doesn't have to be a pure virtual base,
especially if there is a lot of functionality common to both Dealer and
Player, however, up the chain, the further up you go in the inheritance
hierarchy, you *must* eventually find a pure virtual base for just about
every reasonable implementation.  Of course, this is for exceptionally
pure OOP, so my recommendation is to stop at the commonality between the
two and push it into what I've been calling a "Participant" class.  You
know, once you understand the "purist perspective" of OOP, the *hardest*
thing to do is come up with meaningful, correct class and interface
names!  The reason is because *everyone* will have a preconceived
opinion of WHAT a Dealer is, *AND* if you're not very careful in your
class definitions, you'll be caught up in the trap of making them what
you "think" they are rather than what they should be based on good OOAD.

> 
> > There are some subtle nuances to consider when inheriting Dealer from
> > Player.  ISA Dealer a Player?  Using inheritance for specialization is
> > not uncommon, but oftentimes a poorer choice.  A Dealer must abide by a
> > different set of rules than a Player.  Does this "specialization" make
> > the Dealer a unique Player type or does it add confusion to the
> > inheritance path?  A Dealer (in some rule implementations) must hit on
> > 16 and stand on 17, for example, whereas Players do not have to abide by
> > this rule.  A Dealer always has a hidden "hole" card, whereas Players
> > oftentimes do not.  Now that there are some very distinct differences
> > between Players and Dealers, it almost suggests a different base class
> > for both rather than a Dealer is a kind of Player.  ...not that you can
> > not facilitate an implementation where a Dealer ISA Player, but is it a
> > really good use of inheritance?  Perhaps both are kinds of Participants?
> > ...or some other, more generic base where there can be a virtual
> > implementation or pure virtual base class for your derived classes to
> > "follow."
> 
> COMMENTS:
> 
> Since the Dealer is also a player why would you want to re-implement the
> Player code in the Dealer as well. Does this not break the use goal of OO?

Participant

Said it to begin with, said it again.  Shove the common code into the
base, derive the Dealer and Player from Participant not from one
another.  That's because you are effectively saying that a Dealer is ALL
THAT A Player IS all the time forever until your code leaves the world
and is no longer supported.  So, as a Player decides, so must a Dealer. 
So as a Player plays, so must a Dealer.  What happens when you want a
DEALER who does not play? ...say in Poker?  Your Dealer class now
isn't.  That is what OO is all about.  That is the genuinely hard to
achieve aspect of reusability that is so rarely properly implemented by
programmers EVERYWHERE, not just here and not just you.  Please do not
take any thing said here personally.  It is OK to not get some of these
advanced OO topics right the first time or two.  I'll be the first to
admit that I'm still learning some of the more esoteric elements myself!

> After all does the Dealer really abide by different rules than the player,
> or is it that some Dealer operations are done different? For example both
> need to know how ask for a card, both have to know how to "hold" a hand (no
> more cards), both have to know their own name, both need to be able to show

Common OO malignancy.  The "rules" that govern play are not what a
Dealer or Player IS. (Are :)

A Player ISA "player" at a BlackJack table or a Craps table....that is
OO.  Just because you're writing a BJ game, doesn't mean you're "right"
to change what they are :)  You can do it.  C++ will let you, but the
"laws" of OO say that you're not supposed to...that's how reuse is kept
a dream.  A OO-correct implementation would use an appropriate interface
and hidden decision support mechanism so that Player "knows" how to
"play" based on the "Game" and the rules of the "Table"...if it starts
to sound like a lot of work, well, I didn't make these rules.  It isn't
even my job as a "self-appointed" enforcer to share them with you or
anyone; but as an OO programmer, anything less is an injustice to those
who haven't yet "seen the light."  Hopefully you won't feel that I'm
picking you apart in this public forum, it is not my intention at all. 
You're more than welcome to consider my points and say, Rob is full of
crap.  I'm going to do it my way.  Or, you can learn something from what
was taught to me by an OO "master."  I didn't learn a lot of these
lessons without making some "arguments" of my own, but luckily, I was in
a position where I knew that the person teaching me was a master OO
programmer.  I was able to "trust" in what he said because I knew that I
was a "student" and that he was a master.  I'm not suggesting anything
here at all.  What I do know is that a lot of people with some strong
skills in some areas of programming do not necessarily ever become
master OO programmers.  Real OO is not for everyone.  Remember my
comments on the "art" involved in it.  I have a 30 page test I give
programmer candidates to try to get a handle of their level of mastery
of the mechanics *and* the artistic portions of OO.  I figure that if
the guys and gals I hire are strong mechanics, I can bang them in the
head enough to get them to learn at least good design *practices and
procedures* even if I can't teach them the "art form" of it.  I don't
consider myself a master nor do any of the masters I know :)  I have had
plenty of opportunity to learn much from just about every possible
computer user from sheer novice to world-renown experts.  Something that
I'm quite sure is that I'll never know it all and if I ever quit
learning from others, I'll be obsolete.

> their hand, and so forth. Take your example of a hit. Both the Player and
> the Dealer have to know how to take a "hit". The actual operation of a hit
> is different for both but since both are required this function would it not
> be best to override the player hit method for the dealer? This way we get
> all the other operations without recoding.
> 
> >
> > It is simple to do. Just remember to separate the process from display.
> This
> 
> > Separation of Data manipulation from Presentation of the Data is a
> > common architectural theme.  Microsoft calls it "Document/View," where
> > the document is the data and the view is the presentation of the data.
> > The Doc is oftentimes passed to a presentation-centric "view" that knows
> > how to present the data based on the needs of the windowing subsystem
> > and implementor's requirements for the presentation of a particular set
> > of data.  This "close coupling" of data and presentation tend to create
> > two pieces of code that are somewhat dependent on each other while
> > separating functionality on a "role" basis.  However, careful observance
> > of Microsoft's MFC-based implementation of D/V will find an
> > intelligently established set of relationships between base classes that
> > must be subclassed by users for their own D/V implementations.  Behind
> > the scenes, MS has given the programmer as much language "training" and
> > good language feature usage "principles" as possible then left it up to
> > them to simply fill in the blanks with their specific implementation
> > without too much concern for future bending of the rules of good OOP.
> 
> COMMENT:
> 
> This idea is not a Microsoft idea. For those of use who was writing platform
> independent code years ago, we had to do this type of architecture just to
> keep from rewriting our whole application just to move it to a new platform.

Nobody suggested that it was Microsoft's idea, rather they simply did a
good job at successfully implementing it.  It is easy to bash them. 
We're a population of "underdog supporters" and we rebel against all Big
Dogs (whether or not they unfairly crush their competition.).

> 
> 
> COMMENT:
> 
> No offence taken. Yes Microsoft does have some good software. Project, Power
> Point, and Excel are examples of some of the best software for their areas.

Power Point was called Power Pig for the longest time...for the obvious
reason.

> But SourceSafe, Wind Word, and Project Central are all but total failures

I guess that it depends on what a total failure is.  Each (do you mean
MS Project?) have been tremendously successful in terms of sales.  As a
software company, that is how you gauge your success.  Does it produce
revenue?  If you look around at the competition, where is WordStar,
where is WordPerfect...they are dead or dying.  I'm somewhat excited by
AbiWord.  It isn't quite there yet, but it is at least close enough to
be used every day.

> and they are still in use because of the acceptance of software in any state
> from a vendor because the vendor said it has to be that way. This is the
> disservice for the customer that has to be changed by all of us in the
> industry.
> 

...big snip...

> 
> >
> > Thank You,

You're welcome.

> >
> > David Demland
> 


> Take Care.
> 
> Rob!

This signature block has been recycled from 100% post-consumer electrons
and is now sanitized for your comfort and convenience!