Design Lesson 2

Copyright © 直通硅谷

http://www.zhitongguigu.com

Object-Oriented Design

  • Given a technical/real-world problem
  • Simplify to basic parts
  • Sketch out the classes and methods
  • Think like a designer for a game

Copyright © 直通硅谷

http://www.zhitongguigu.com

4 Steps

  1. Clarify the question
  2. Start with main objects
  3. Try link them up
  4. Action with examples

Copyright © 直通硅谷

http://www.zhitongguigu.com

Clarify the Question

  1. Interviewer is hiding the detail
  2. Ask like a co-worker
  3. who, where, when, why, how, what
    1. Internal/External/International user
    2. FE/BE
    3. Rush hour? Flat? Normal distributed?
    4. Current solution not good enough
    5. How would you like to implement
    6. What's the specific requirement

Copyright © 直通硅谷

http://www.zhitongguigu.com

Start with Main Objects

  1. Consider the main parts
  2. "Design a Parking Lot"
    • Parking Lot
      • Controller
      • ParkingSpace
        • RegularParkingSpace
        • HandicappedParkingSpace
        • CompactParkingSpace
        • EV, RV, ExpectedMother, Truck
      • Car, Sign, Floor, Parker, PayStation, Valet

Copyright © 直通硅谷

http://www.zhitongguigu.com

Try Link Them Up

  1. Relationship between objects
  2. Member of.
  3. Inherit & Implement
  • ParkingLot should have an array of Floors
  • Floor should have an array of ParkingSpace
  • RegularPS, CompactPS, HandicappedPS... inherit from ParkingSpace
  • Sign should be Enum: Full, Empty, Invalid

Copyright © 直通硅谷

http://www.zhitongguigu.com

Action with Examples

  1. Already have the basic outline of your design
  2. Take a example and walk through
  3. Consider the key actions
  4. Update the design if forgot any object

Copyright © 直通硅谷

http://www.zhitongguigu.com

  • SpaceController
    • assignSpace
    • getCar
  • Floor
    • getVacantSpace#
    • isFull
  • Space
    • sign
    • type
  • Car
    • Plate#
    • type

Copyright © 直通硅谷

http://www.zhitongguigu.com

Design Blackjack (21 点)

Copyright © 直通硅谷

http://www.zhitongguigu.com

Design Blackjack

  1. Clarify the question
  2. Start with main objects
  3. Try link them up
  4. Action with examples

Copyright © 直通硅谷

http://www.zhitongguigu.com

BlackJack: A +  FaceCard

21: All cards add up to 21

No Joker

Clarify the Question

Copyright © 直通硅谷

http://www.zhitongguigu.com

  1. Deck
  2. Card -> BJCard
  3. Suit
  4. Player(Hand) -> BJHand
  5. Dealer (Automator)
  6. MainMethodClass

(Heat, Spade, Club, Diamond)

Start with Main Objects

Copyright © 直通硅谷

http://www.zhitongguigu.com

Try Link Them Up

Copyright © 直通硅谷

http://www.zhitongguigu.com

  • Deck
    1. Shuffle
    2. DealCards
  • Card -> BJCard
    1. Value (Min/Max)
    2. Suit
    3. isFaceCard
  • Player(Hand) -> BJHand
    1. addCard
    2. getScore
    3. isBusted
    4. isBlackJack

Action with Examples

  • Dealer (Automator)
    1. init (Deck/Hand)
    2. getBlackJack
    3. playHand
    4. getWinner
  • MainMethodClass
    1. init
    2. if (hasBJ) 
    3. else (playHand)
    4. getWinner

Copyright © 直通硅谷

http://www.zhitongguigu.com

import java.util.ArrayList;

public class Main {
    
    public static void main(String[] args) {
        int numHands = 8;
        
        BlackJackGameAutomator automator = new BlackJackGameAutomator(numHands);
        automator.initializeDeck();
        boolean success = automator.dealInitial();
            if (!success) {
                System.out.println("Error. Out of cards.");
            } else {
            System.out.println("-- Initial --");
            automator.printHandsAndScore();
            ArrayList<Integer> blackjacks = automator.getBlackJacks();
            if (blackjacks.size() > 0) {
                System.out.print("Blackjack at ");
                for (int i : blackjacks) {
                    System.out.print(i + ", ");
                }
                System.out.println("");
            } else {
                success = automator.playAllHands();
                if (!success) {
                    System.out.println("Error. Out of cards.");
                } else {
                    System.out.println("\n-- Completed Game --");
                    automator.printHandsAndScore();
                    ArrayList<Integer> winners = automator.getWinners();
                    if (winners.size() > 0) {
                        System.out.print("Winners: ");
                        for (int i : winners) {
                            System.out.print(i + ", ");
                        }
                        System.out.println("");
                    } else {
                        System.out.println("Draw. All players have busted.");
                    }
                }
            }
        }
    }

}

Copyright © 直通硅谷

http://www.zhitongguigu.com

import java.util.ArrayList;

public class BlackJackGameAutomator {
    private Deck<BlackJackCard> deck;
    private BlackJackHand[] hands;
    private static final int HIT_UNTIL = 16;
    
    public BlackJackGameAutomator(int numPlayers) {
        hands = new BlackJackHand[numPlayers];
        for (int i = 0; i < numPlayers; i++) {
            hands[i] = new BlackJackHand();
        }
    }
    
    public void initializeDeck() {
        ArrayList<BlackJackCard> cards = new ArrayList<BlackJackCard>();
        for (int i = 1; i <= 13; i++) {
            for (int j = 0; j <= 3; j++) {
                Suit suit = Suit.getSuitFromValue(j);
                BlackJackCard card = new BlackJackCard(i, suit);
                cards.add(card);
            }
        }
        deck = new Deck<BlackJackCard>();
        deck.setDeckOfCards(cards);
        deck.shuffle();
    }

    public boolean dealInitial() {
        for (BlackJackHand hand : hands) {
            BlackJackCard card1 = deck.dealCard();
            BlackJackCard card2 = deck.dealCard();
            if (card1 == null || card2 == null) {
                return false;
            }
            hand.addCard(card1);
            hand.addCard(card2);    
        }
        return true;
    }
    
    public ArrayList<Integer> getBlackJacks() {
        ArrayList<Integer> winners = new ArrayList<Integer>();
        for (int i = 0; i < hands.length; i++) {
            if (hands[i].isBlackJack()) {
                winners.add(i);
            }
        }
        return winners;
    }
    
    public boolean playAllHands() {
        for (BlackJackHand hand : hands) {
            if (!playHand(hand)) {
                return false;
            }
        }
        return true;
    }

    public boolean playHand(BlackJackHand hand) {
        while (hand.score() <= HIT_UNTIL) {
            BlackJackCard card = deck.dealCard();
            if (card == null) {
                return false;
            }
            hand.addCard(card);
        }
        return true;
    }    

    public ArrayList<Integer> getWinners() {
        ArrayList<Integer> winners = new ArrayList<Integer>();
        int winningScore = 0;
        for (int i = 0; i < hands.length; i++) {
            BlackJackHand hand = hands[i];
            if (!hand.busted()) {
                if (hand.score() > winningScore) {
                    winningScore = hand.score();
                    winners.clear();
                    winners.add(i);
                } else if (hand.score() == winningScore) {
                    winners.add(i);
                }
            }
        }
        return winners;
    }
    
    public void printHandsAndScore() {
        for (int i = 0; i < hands.length; i++) {
            System.out.print("Hand " + i + " (" + hands[i].score() + "): ");
            hands[i].print();
            System.out.println("");
        }
    }
}

Copyright © 直通硅谷

http://www.zhitongguigu.com

public abstract class Card {
    private boolean available = true;

    protected int faceValue;
    protected Suit suit;

    public Card(int c, Suit s) {
        faceValue = c;
        suit = s;
    }
    
    public abstract int value();
    
    public Suit suit() { 
        return suit; 
    }
    
    public boolean isAvailable() {
        return available;
    }
    
    public void markUnavailable() {
        available = false;
    }
    
    public void markAvailable() {
        available = true;
    }
    
    public void print() {
        switch (suit) {
        case Club:
            System.out.print("♣");
            break;
        case Heart:
            System.out.print("♥");
            break;
        case Diamond:
            System.out.print("♦");
            break;
        case Spade:
            System.out.print("♠");
            break;            
        }
        String[] faceValues = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"};
        System.out.print(faceValues[faceValue - 1]);
        System.out.print(" ");
    }
}

Copyright © 直通硅谷

http://www.zhitongguigu.com

public enum Suit { 
    Club (0),
    Diamond (1),
    Heart (2),
    Spade (3);
    
    private int value;
    private Suit(int v) {
        value = v;
    }
    
    public int getValue() {
        return value;
    }
    
    public static Suit getSuitFromValue(int value) {
        switch (value) {
        case 0:
            return Suit.Club;
        case 1:
            return Suit.Diamond;
        case 2:
            return Suit.Heart;
        case 3: 
            return Suit.Spade;
        default:
                return null;
        }
    }
}

Copyright © 直通硅谷

http://www.zhitongguigu.com

public class BlackJackCard extends Card {
    public BlackJackCard(int c, Suit s) {
        super(c, s);
    }
    
    public int value() {
        if (faceValue >= 11 && faceValue <= 13) { // Face card
            return 10;
        } else { // Number card
            return faceValue;
        }
    }
    
    public int minValue() {
        return isAce() ? 1 : value();
    }
    
    public int maxValue() {
        return isAce() ? 11 : value();
    }
    
    public boolean isAce() { 
        return faceValue == 1;
    } 
    
    public boolean isFaceCard() {
        return faceValue >= 11 && faceValue <= 13;
    }
}

Copyright © 直通硅谷

http://www.zhitongguigu.com

import java.util.ArrayList;

public class Deck <T extends Card> {
    private ArrayList<T> cards;
    private int dealtIndex = 0; // marks first undealt card
    
    public void setDeckOfCards(ArrayList<T> deckOfCards) {
        cards = deckOfCards;
    }
    
    public void shuffle() {
        for (int i = 0; i < cards.size(); i++) {
            int j = randomIntInRange(i, cards.size() - i - 1);
            T card1 = cards.get(i);
            T card2 = cards.get(j);
            cards.set(i, card2);
            cards.set(j, card1);
        }
    }
    
    public T dealCard() {
        if (remainingCards() == 0) {
            return null;
        }
        T card = cards.get(dealtIndex);
        card.markUnavailable();
        dealtIndex++;
        return card;        
    }
    
    public void print() {
        for (T card : cards) {
            card.print();
        }
    }

    private int randomIntInRange(int min, int max) {
        int diff = max - min + 1;
        return (int) (Math.random() * diff) + min;
    }
    
    private int remainingCards() {
        return cards.size() - dealtIndex;
    }
}

Copyright © 直通硅谷

http://www.zhitongguigu.com

import java.util.ArrayList;

public class Hand <T extends Card> {
    protected ArrayList<T> cards = new ArrayList<T>();
    
    public int score() {
        int score = 0;
        for (T card : cards) {
            score += card.value();
        }
        return score;
    }
    
    public void addCard(T card) {
        cards.add(card);
    }    
    
    public void print() {
        for (Card card : cards) {
            card.print();
        }
    }    
}

Copyright © 直通硅谷

http://www.zhitongguigu.com

import java.util.ArrayList;

public class BlackJackHand extends Hand<BlackJackCard> {
    
    public int score() {
        ArrayList<Integer> scores = possibleScores();
        int maxUnder = Integer.MIN_VALUE;
        int minOver = Integer.MAX_VALUE;
        for (int score : scores) {
            if (score > 21 && score < minOver) {
                minOver = score;
            } else if (score <= 21 && score > maxUnder) {
                maxUnder = score;
            }
        }
        return maxUnder == Integer.MIN_VALUE ? minOver : maxUnder;
    }
    
    private ArrayList<Integer> possibleScores() {
        ArrayList<Integer> scores = new ArrayList<Integer>();
        if (cards.size() == 0) {
            return scores;
        }
        for (BlackJackCard card : cards) {
            addCardToScoreList(card, scores);
        }
        return scores;
    }
    
    private void addCardToScoreList(BlackJackCard card, ArrayList<Integer> scores) {
        if (scores.size() == 0) {
            scores.add(0);
        } 
        int length = scores.size();
        for (int i = 0; i < length; i++) {
            int score = scores.get(i);
            scores.set(i, score + card.minValue());
            if (card.minValue() != card.maxValue()) {
                scores.add(score + card.maxValue());
            }
        }
    }
    
    public boolean busted() {
        return score() > 21;
    }
    
    public boolean is21() {
        return score() == 21;
    }
    
    public boolean isBlackJack() {
        if (cards.size() != 2) {
            return false;
        }
        BlackJackCard first = cards.get(0);
        BlackJackCard second = cards.get(1);
        return first.isAce() && second.isFaceCard() || second.isAce() && first.isFaceCard();
    }
}
Made with Slides.com