Upload
buidieu
View
215
Download
0
Embed Size (px)
Citation preview
Monopoly Use Case• Text for this use case is very different than the NextGen POS problem, as it is
a simple simulation. – Game rules are captured in another document, rather than in the
use case.
Use Case UC1: Play Monopoly GameScope: Monopoly applicationLevel: user goalPrimary Actor: ObserverStakeholders and Interests:
- Observer: Wants to easily observe the output of the game simulation.Main Success Scenario:1. Observer requests new game initialization, enters number of players.2. Observer starts play.3. System displays game trace for next player moveRepeat step 3 until a winner or Observer cancels.
SSD
We will focus on this one.
We didn't write a detailed use case or an operation contractas most people know the rules.Focus is the design issues, not the requirements.
The Game-Loop Algorithm• First, some terminology:
turn -- a player rolling the dice and moving the pieceround -- all the players taking one turn
Now the game loop:
for N roundsplayRound()
playRound()for each Player p
p takes a turn
Assumption: Iteration-1 version does not have a winner, so the simulation simply runs for N rounds.
Who Takes a Turn?• Let’s apply Information Expert.
Information Needed Who Has the Information?current location of the player (to know the starting point of a move)
Taking inspiration from DM, a Piece knows its Square and a Player knows its Piece. Therefore, a Player software object could know its location.
the two Die objects (to roll them and calculate their total)
Taking inspiration from DM, MonopolyGame is a candidate since we think of the dice as being part of the game.
all the squares - the square organization (to be able to move to the correct new square)
Board is a good candidate.
Who Takes a Turn?• Three partial information experts for the "take a turn" responsibility:
– Player, MonopolyGame, and Board.• Why should be primary?• Guideline: When there are multiple partial information experts to choose from
place the responsibility in the dominant information expert-the object with majority of the information. This tends to best support Low Coupling.– Unfortunately, in this case, are all rather equal, each with about
one-third of information-no dominant expert.• Another guideline to try:
Guideline: When there are alternative design choices, consider the couplingand cohesion impact of each, and choose the best.– MonopolyGame is already doing some work, so giving it more
work impacts its cohesion, especially when contrasted with a Player an Board object, which are not doing anything yet.
– But we still have a two-way tie with these objects.
Who Takes a Turn?• Guideline: Consider probable future evolution of the software objects and the
impact in terms of Information Expert, cohesion, and coupling.
• For example, in iteration-1, taking a turn doesn't involve much information.
• However, consider the complete set of game rules in a later iteration. Then, taking a turn it’s not only about rolling the dice and moving the piece.
• Taking a turn can involve buying a property that the player lands on, if the player has enough money or if its color fits in with the player's "color strategy."
• What object would be expected to know a player's cash total?• Answer: a Player • What object would be expected to know a player's color strategy?• Answer: a Player
Taking a TurnTaking a turn means:1. calculating a random number total between 2 and 12
– (the range of two dice)2. calculating the new square location3. moving the player's piece from an old location to a new square location
• First, calculating a new random faceValue involves changing information in the Die, – so by Expert Die should be able to "roll" itself, and answer its faceValue.
• Second, the new square location problem: By LRG, it's reasonable that a Board knows all its Squares. – Then by Expert a Board will be responsible for knowing a new square
location, given an old square location, and some offset (the dice total).• Third, the piece movement problem: By LRG, it's reasonable for a Player to
know its Piece, and a Piece its Square location. – Then by Expert a Piece will set its new location.
Command-Query Separation Principle//style #1; used in the solutionpublic void roll() {
faceValue = //random num generation}public int getFaceValue() {
return faceValue;}
Why not make roll non-void and combine these two functions so that the rollmethod returns the new face Value, as follows?
//style #2; why is this poor?public int roll(){
faceValue = //random num generationreturn faceValue;
}
Command-Query Separation PrincipleThis principle states that every method should either be:• a command method that performs an action (updating,
coordinating, ..– often has side effects such as changing the state of objects, and is
void• a query that returns data to the caller and has no side effects
– it should not change the state of any objects
But, a method should not be both.• The roll method is a command - it has the side effect of
changing the state of the Die's faceValue. – Therefore, it should not also return the new faceValue, as then the
method also becomes a kind of query and violates the "must be void" rule.
Command-Query Separation Principle• Related to Principle of Least Surprise in software development.• What can happen when one violates CQS…
Missile m = new Missile();
String name = m.getName(); //looks harmless to me!
public class Missile {…public String getName() {
launch(); //launch missile?return name;
} //end of class
Class Squarepublic class Square {
private String name;private int index;
/** Creates a new instance of Square */public Square(String name, int index) {
this.name = name;this.index = index;
}
public String getName() {return name;}public int getIndex() {return index;}
}
Class Piecepublic class Piece {
Square location;
/** Creates a new instance of Piece */public Piece(Square location) {
this.location = location;}
public Square getLocation() {return location;}public void setLocation(Square location) {this.location = location;}
}
Class Diepublic class Die{
public static final int MAX = 6;private int faceValue;
public Die(){roll( );
}
public void roll() {face Value = (int) ( ( Math.random( ) * MAX ) + 1 );
}
public int getFaceValue() {return face Value;
}}
Class Boardpublic class Board {private static final int SIZE = 40;private List<Square> squares;/** Creates a new instance of Board */public Board() {
squares = new ArrayList<Square>(SIZE);buildSquares();
}
public Square getSquare(Square start, int distance) {int endIndex = ( start.getIndex() + distance ) % Board.SIZE;return squares.get(endIndex);
}
public Square getStartSquare() {return squares.get(0);
}
private void buildSquares() {for(int i=0; i<SIZE; i++) {
Square square = new Square("Square "+i, i);squares.add(square);
}}
}
Class Playerpublic class Player {private String name;private Piece piece;private Board board;private Die[] dice;
public Player(String name, Board board, Die[] dice) {this.setName(name);this.board = board;this.dice = dice; this.piece = new Piece(board.getStartSquare());
}
public void takeTurn() {System.out.println(name + " taking a turn...");
int rollTotal = 0;for(int i=0; i<dice.length; i++) {
dice[i].roll();rollTotal += dice[i].getFaceValue();
}
Square newLoc = board.getSquare(this.piece.getLocation(), rollTotal);
piece.setLocation(newLoc);
System.out.println(" new location is " + getLocation().getIndex());}
Class Player
public Square getLocation() {return this.piece.getLocation();
}
public String getName() {return name;
}
public void setName(String name) {this.name = name;
}}
Class MonopolyGamepublic class MonopolyGame {
private static final int ROUNDS_TOTAL = 20;private static final int PLAYERS_TOTAL = 2;private static final int DICE_TOTAL = 2;
private List<Player> players = new ArrayList<Player> (PLAYERS_TOTAL);private Board board = new Board();private Die[] dice = new Die [DICE_TOTAL];
public MonopolyGame() {for(int i=0; i<DICE_TOTAL; i++)
dice[i] = new Die();
for(int i=0; i<PLAYERS_TOTAL; i++) {Player player = new Player("Player " + i, board, dice);players.add(player);
}}