Object-Oriented Design Interview

Course Content

Object-Oriented Design Interview

14 sections · 29 lessons

Blackjack: rules, requirements and the hand-centred model


Tic tac toe has one rule; blackjack has twenty, and they vary from casino to casino. That makes this a problem about two things — where rules live, and where scoring lives. This lesson covers the rules of the game, the questions and requirements, and the model, whose central decision is proved right by one word: split.

One round, end to endPlayersplace betsDeal twocards eachEach player actsDealerdraws to 17Settle every betEverything the design must support happens somewhere in this sequence.
Tracing one round out loud is how you find the objects: the round itself is the missing class.

The rules, in six lines

Not everyone has played, so here is the whole game. It is invented-casino generic; specific rules vary, which is itself part of the problem.

  1. Players bet, then everyone including the dealer gets two cards.
  2. Number cards score their face value, picture cards score 10, and an ace scores 1 or 11, whichever is better for the hand.
  3. A player takes actions — hit (take a card), stand (stop), double (double the bet, take exactly one more card), split (turn a pair into two hands).
  4. Going over 21 is a bust and loses immediately.
  5. The dealer then plays by a fixed rule, typically "draw until 17 or more, then stop".
  6. Hands closer to 21 than the dealer win; equal is a push (bet returned).

Why this problem is different from tic tac toe

Tic tac toe has one rule. Blackjack has twenty, and they vary by casino: whether the dealer draws on a soft 17, how many times you may split, whether you may double after splitting, whether blackjack pays 3:2 or 6:5. Rule encapsulation is the point. A design where those rules are constants scattered through the game loop cannot represent a second casino, and the interviewer will ask about exactly that.

The four questions that change the model

1. "How many decks, and how many players?" Casinos deal from a shoe of several decks, reshuffled at a marker rather than after every hand. That detail matters for the card-counting extension and costs one class. Assume six decks and up to five players.

2. "Which actions are allowed — hit, stand, double, split, insurance, surrender?" Splitting is the one that tests your model, because it turns one player's single hand into several independent hands. Ask specifically. Assume hit, stand, double, and split; treat insurance and surrender as extensions.

3. "Are betting and chips in scope?" Settlement — who gets paid what — is where blackjack has real logic (blackjack pays 3:2, a push returns the bet, a double stakes twice). Assume bets are in scope, and chip inventory and table limits are not.

4. "What exactly are the dealer's rules?" Ask the soft-17 question explicitly: "Does the dealer draw on a soft 17 — that is, an ace-six? It changes the house edge and I want it to be configuration rather than a constant." This question is a strong signal, because it shows you know rules vary and you have decided where variation lives.

Assumptions this lesson makes

  • Six decks in a shoe, reshuffled at a penetration marker.
  • Up to five players plus a dealer.
  • Actions: hit, stand, double down, split. Insurance and surrender are extensions.
  • Bets in scope; blackjack pays 3:2; dealer stands on all 17s — all configurable.
  • Single table, single thread. Concurrency is not this problem's question.

Requirements

Functional requirements

Text
1. Place a bet for each player before the deal2. Deal two cards to each player and to the dealer (one dealer card face up)3. Score a hand, handling aces as 1 or 114. Take player actions in turn: hit, stand, double, split5. Play the dealer's hand by a fixed rule6. Settle every hand against the dealer and pay or collect

Requirement 3 gets its own treatment (the ace problem, in code) because it is a small piece of code that separates careful candidates from hasty ones.

Rules as an object, stated earlyRules scattered as constants• 17 hardcoded in the dealer loop• Blackjack payout buried in settlement• Every house variation edits codeOne Rules object• Dealer stands on soft 17: a flag• Blackjack pays 3 to 2: a field• A new house is a new Rules instance
Naming the Rules object in the requirements phase pre-empts half the extension questions.

Non-functional requirements

N1. Rule variations must be configuration, not code. Casinos differ. A design that can be pointed at a rules object and behave like a different casino is the target.

N2. A human player and a bot must be interchangeable. Same reason as tic tac toe: the game loop should not know which it is talking to.

N3. The shoe must not be reshuffled per hand. Cards dealt stay dealt until the reshuffle marker, which is what makes card counting possible and the simulation realistic.

What is cut

Text
CUT (named, not forgotten)- Chip denominations and physical chip trays- Table limits, side bets beyond insurance- Multi-table casino management, player accounts- Any user interface or animation- Shuffle randomness quality (a seeded shuffle is enough for the design)

The rules object, stated early

Requirement N1 deserves a concrete shape in the requirements phase, because everything else refers to it:

Java
public class GameRules {    private final int decksInShoe;              // 6    private final boolean dealerHitsSoft17;     // false    private final Ratio blackjackPayout;        // 3:2    private final int maxSplits;                // 3    private final boolean doubleAfterSplitAllowed;    private final boolean surrenderAllowed;}

Six fields, and every one of them is a rule that a real casino varies. Putting this class on the board in minute eight and saying "every rule that differs between casinos lives here, and nothing else reads a constant" is a compact way to satisfy N1 before writing any other class.

Finding the objects

The candidate nouns

Game, round, table, deck, shoe, card, rank, suit, hand, player, dealer, bet, chip, action, score, outcome.

Hand is where the problem livesHandThe cards heldscore(), aces includedisSoft and isBustThe bet on itSplit produces two
Scoring belongs on Hand, not Player, because splitting gives one player two independently bet hands.

The decision that carries the problem: Hand owns scoring

The instinct is to put score() on Player — a player has cards, a player has a total.

It is wrong, and splitting is what proves it. When a player splits a pair of eights, they now have two hands, each with its own cards, its own bet, its own actions, and its own outcome. One can bust while the other wins. A score() on Player has nothing coherent to return.

Java
public class Hand {    private final List<Card> cards = new ArrayList<>();    private Bet bet;    private HandStatus status;        // ACTIVE, STOOD, BUST, BLACKJACK, SURRENDERED    public int bestScore()  { … }     // see the ace problem lesson    public boolean isSoft() { … }     // has an ace counted as 11    public boolean isBust() { return bestScore() > 21; }    public boolean isBlackjack() { return cards.size() == 2 && bestScore() == 21; }    public boolean canSplit() {        return cards.size() == 2 && cards.get(0).getRank() == cards.get(1).getRank();    }}public class Player {    private final String name;    private Money chips;    private final List<Hand> hands = new ArrayList<>();   // usually one; more after a split    private final MoveStrategy strategy;}

Say it out loud: "Scoring goes on Hand, not Player, because a split gives one player two hands that win or lose independently. The bet goes on the hand too, for the same reason — each split hand carries its own stake."

That sentence answers a question the interviewer was going to ask in the extensions, twenty minutes early. This is the same lesson as the tic tac toe objects (win detection belongs to the board): put behaviour with the data it needs, and the data here is the cards of one hand.

Deck and shoe

Two classes, and the distinction is real:

Java
public class Deck {                              // 52 cards, a factory really    public static List<Card> standardDeck() { … }}public class Shoe {    private final Deque<Card> cards;    private final int reshuffleThreshold;         // reshuffle when fewer remain    public Card draw() {        if (cards.size() < reshuffleThreshold) refillAndShuffle();        return cards.pop();    }}

Shoe is where the interesting behaviour is — drawing, depletion, and the reshuffle rule. Deck is close to a static factory. Say that: "Deck is nearly a factory method; the real object is Shoe, which is what gets drawn from and reshuffled."

Dealer: a player, or not?

A genuine modelling question with two defensible answers, and the interviewer may push on it.

Dealer extends Player. Tempting — the dealer has a hand and takes actions. But the dealer has no chips, never bets, never splits, never doubles, and does not choose anything. Most of Player is inapplicable, and inherited methods that make no sense are the Liskov violation from the SOLID reference.

Dealer as its own class. It holds one hand and a rule for when to draw:

Java
public class Dealer {    private Hand hand;    private final GameRules rules;    public boolean shouldDraw() {        int score = hand.bestScore();        if (score < 17) return true;        return score == 17 && hand.isSoft() && rules.dealerHitsSoft17();    }}

Recommend the second, and give the reason: "I'll keep Dealer separate rather than subclassing Player, because the dealer has no chips and makes no decisions — inheriting a placeBet method the dealer must refuse is a Liskov problem. What they share is a Hand, and they both hold one."

The rest of the model

ClassIts one-sentence job
Game / RoundRuns one round from bets to settlement
ShoeSupplies cards and reshuffles at the marker
CardA rank and a suit; immutable
HandHolds cards, scores them, and knows its own status
PlayerA person with chips, a strategy, and one or more hands
DealerHolds a hand and knows when to draw
BetAn amount staked on one hand, and its payout
GameRulesEvery rule that differs between casinos
MoveStrategyChooses an action given a hand and the dealer's up-card