As a simple example we can imagine we are to write a card game with multiple players. Any card game actually, the point is that the players have hole cards which they don't share with others. Not even with the rest of the code. This project implements a simplified Blackjack game what perfectly serves the purpose of this post. This is the class for the participating players.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Player extends Entity<PlayerID> { | |
private final List<Card> cards; | |
private boolean stopped; | |
public Player(PlayerID playerID, List<Card> cards) { | |
super(playerID); | |
Validate.notNull(playerID); | |
Validate.notNull(cards); | |
this.cards = cards; | |
} | |
public boolean notStopped() { return !stopped();} | |
public boolean stopped() { return stopped;} | |
public void stand() { this.stopped = true;} | |
/** | |
* Important that the logic should be where the data is. This yields rich | |
* object model. | |
* | |
* @return | |
*/ | |
public int score() { | |
int score = 0; | |
int aceCounter = 0; | |
for (Card card : cards) { | |
score += card.value(); | |
if (card.rank == Rank.ACE) { | |
aceCounter++; | |
} | |
} | |
// if player has two ACES, then one has a value of 1 | |
if (aceCounter > 1) { | |
score -= 10; | |
} | |
return score; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//version one - simple getter | |
class Player { | |
... | |
List<Cards> getCards() { return Lists.newArrayList(this.cards);} | |
... | |
} | |
//version two - a new immutable object for that aspect of the Player | |
// so the Player internals are not exposed directly | |
class PlayerView { | |
private final PlayerID id; | |
private final List<Cards> cards; | |
//constructor and getters | |
} | |
class Player { | |
... | |
PlayerView getView() {...} | |
... | |
} | |
In Clojure classes are not used, instead functions operate on associative information models (@Copyright Rich Hickey), namely maps, lists, vectors, sets. There is no information hiding, the player is represented something like this
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; a player representation | |
{:id 123 | |
:cards [[2 :spades] [:king :clubs] [10 :diamonds]] | |
:stopped false} | |
;; a function calculating the score | |
(defn score-hand [cards] | |
"Calculates the score for the hand" | |
(let [sum (reduce + (map card-value cards)) | |
ace? #(= :ace (last %)) | |
ace-count (count (filter ace? cards))] | |
(if (> ace-count 1) | |
(- sum 10) | |
sum))) |
No comments :
Post a Comment