Figure 9-1, the class implementor, the class extender, and the class user role. Developer Bernd Bruegge & Allen H. Dutoit Class User Call Class Class Implementor Realize Class Class Extender Refine Class Object-Oriented Software Engineering: Using UML, Patterns, and Java 1 Figure 9-2, ARENA Game abstract class with user classes and extender classes. League Game 1 * Tournament Bernd Bruegge & Allen H. Dutoit TicTacToe Object-Oriented Software Engineering: Using UML, Patterns, and Java Chess 2 Figure 9-3, Declaration for the Tournament class. Tournament -maxNumPlayers: int public class Tournament { private int maxNumPlayers; /* Other fields omitted */ public public public public public public +getMaxNumPlayers():int +getPlayers(): List +acceptPlayer(p:Player) +removePlayer(p:Player) +isPlayerAccepted(p:Player):boolean Tournament(League l, int maxNumPlayers) int getMaxNumPlayers() {…}; List getPlayers() {…}; void acceptPlayer(Player p) {…}; void removePlayer(Player p) {…}; boolean isPlayerAccepted(Player p) {…}; /* Other methods omitted */ } Bernd Bruegge & Allen H. Dutoit Object-Oriented Software Engineering: Using UML, Patterns, and Java 3 Figure 9-4, Examples of invariants, preconditions, and postconditions in OCL attached as notes to the UML model. «invariant» getMaxNumPlayers() > 0 «precondition» getNumPlayers() < getMaxNumPlayers() Tournament «precondition» !isPlayerAccepted(p) «precondition» isPlayerAccepted(p) Bernd Bruegge & Allen H. Dutoit -maxNumPlayers: int +getNumPlayers():int +getMaxNumPlayers():int +acceptPlayer(p:Player) +removePlayer(p:Player) +isPlayerAccepted(p:Player):boolean Object-Oriented Software Engineering: Using UML, Patterns, and Java «postcondition» isPlayerAccepted(p) «postcondition» !isPlayerAccepted(p) 4 Tournament invariant context Tournament inv: self.getMaxNumPlayers() > 0 Bernd Bruegge & Allen H. Dutoit Object-Oriented Software Engineering: Using UML, Patterns, and Java 5 Tournament.acceptPlayer contract context Tournament::acceptPlayer(p) pre: not isPlayerAccepted(p) context Tournament::acceptPlayer(p) pre: getNumPlayers() < getMaxNumPlayers() context Tournament::acceptPlayer(p) post: isPlayerAccepted(p) context Tournament::acceptPlayer(p) post: getNumPlayers() = @pre.getNumPlayers() + 1 Bernd Bruegge & Allen H. Dutoit Object-Oriented Software Engineering: Using UML, Patterns, and Java 6 Tournament.removePlayer contract context Tournament::removePlayer(p) pre: isPlayerAccepted(p) context Tournament::removePlayer(p) post: not isPlayerAccepted(p) context Tournament::removePlayer(p) post: getNumPlayers() = @pre.getNumPlayers() - 1 Bernd Bruegge & Allen H. Dutoit Object-Oriented Software Engineering: Using UML, Patterns, and Java 7 Figure 9-5, Method declarations for the Tournament class annotated with preconditions, postconditions, and invariants public class Tournament { /** The acceptPlayer() operation * assumes that the specified * player has not been accepted * in the Tournament yet. * @pre !isPlayerAccepted(p) * @pre getNumPlayers()<maxNumPlayers * @post isPlayerAccepted(p) * @post getNumPlayers() = * @pre.getNumPlayers() + 1 */ public void acceptPlayer (Player p) {…} /** The maximum number of players * is positive at all times. * @invariant maxNumPlayers > 0 */ private int maxNumPlayers; /** The players List contains * references to Players who are * are registered with the * Tournament. */ private List players; /** The removePlayer() operation * assumes that the specified player * is currently in the Tournament. * @pre isPlayerAccepted(p) * @post !isPlayerAccepted(p) * @post getNumPlayers() = @pre.getNumPlayers() - 1 */ public void removePlayer(Player p) {…} /** Returns the current number of * players in the tournament. */ public int getNumPlayers() {…} /** Returns the maximum number of * players in the tournament. */ public int getMaxNumPlayers() {…} Bernd Bruegge & Allen H. Dutoit } Object-Oriented Software Engineering: Using UML, Patterns, and Java 8 Figure 9-6, Associations among League, Tournament, and Player classes in ARENA. * League +start:Date +end:Date +getActivePlayers() {ordered} * tournaments Tournament +start:Date +end:Date +acceptPlayer(p:Player) * tournaments players * Bernd Bruegge & Allen H. Dutoit * players Player +name:String +email:String Object-Oriented Software Engineering: Using UML, Patterns, and Java 9 Figure 9-7, Example situation with two Leagues, two Tournaments, and five Players. tttExpert:League chessNovice:League winter:Tournament xmas:Tournament start=Dec 21 end=Dec 22 start=Dec 23 end=Dec 25 alice:Player bob:Player marc:Player joe:Player zoe:Player Bernd Bruegge & Allen H. Dutoit Object-Oriented Software Engineering: Using UML, Patterns, and Java 10 Figure 9-8, There are only three basic types of navigation. Any OCL constraint can be built using a combination of these three types. 1. Local attribute Tournament start:Date end:Date 2. Directly related class League 3. Indirectly related class League * * Player * Tournament * * Player Bernd Bruegge & Allen H. Dutoit Object-Oriented Software Engineering: Using UML, Patterns, and Java 11 Examples of constraints using each type of navigation 1. Local attribute context Tournament inv: end - start <= Calendar.WEEK 2. Directly related class context Tournament::acceptPlayer(p) pre: league.players->includes(p) 3. Indirectly related class context League::getActivePlayers post: result = tournaments.players->asSet Bernd Bruegge & Allen H. Dutoit Object-Oriented Software Engineering: Using UML, Patterns, and Java 12 OCL forall quantifier /* All Matches in a Tournament occur within the Tournament’s time frame */ context Tournament inv: matches->forAll(m:Match | m.start.after(t.start) and m.end.before(t.end)) Bernd Bruegge & Allen H. Dutoit Object-Oriented Software Engineering: Using UML, Patterns, and Java 13 OCL exists quantifier /* Each Tournament conducts at least one Match on the first day of the Tournament */ context Tournament inv: matches->exists(m:Match | m.start.equals(start)) Bernd Bruegge & Allen H. Dutoit Object-Oriented Software Engineering: Using UML, Patterns, and Java 14 Figure 9-9, Analysis objects of ARENA identified during the analysis of Announce Tournament use case. TournamentForm applyForTournament() 1 1 TournamentControl * selectSponsors() advertizeTournament() acceptPlayer() announceTournament() 1 * 1 Tournament * * players Player * matches * Match start status name * start end acceptPlayer() removePlayer() schedule() * sponsors * * Advertiser matches * playMove() getScore() Bernd Bruegge & Allen H. Dutoit Object-Oriented Software Engineering: Using UML, Patterns, and Java 15 Figure 9-10, a sequence diagram for the applyForTournament() operation. :Player :TournamentForm :TournamentControl t:Tournament p:Player applyForTournament(p) isPlayerOverbooked(p) getStartDate() getEndDate() getTournaments() tournaments Bernd Bruegge & Allen H. Dutoit Object-Oriented Software Engineering: Using UML, Patterns, and Java 16 Figure 9-11, Adding type information to the object model of ARENA. TournamentForm 1 1 +applyForTournament() * TournamentControl * +selectSponsors(advertisers):List +advertizeTournament() +acceptPlayer(p) +announceTournament() +isPlayerOverbooked():boolean 1 1 Tournament * * players Player * matches * Match +start:Date +status:MatchStatus +name:String * +start:Date +end:Date +acceptPlayer(p) +removePlayer(p) +schedule() * sponsors * * Advertiser matches * +playMove(p,m) +getScore():Map Bernd Bruegge & Allen H. Dutoit Object-Oriented Software Engineering: Using UML, Patterns, and Java 17 Pre- and post-conditions for ordering operations on TournamentControl TournamentControl +selectSponsors(advertisers):List +advertizeTournament() +acceptPlayer(p) +announceTournament() +isPlayerOverbooked():boolean context TournamentControl::selectSponsors(advertisers) pre: interestedSponsors->notEmpty and tournament.sponsors->isEmpty context TournamentControl::selectSponsors(advertisers) post: tournament.sponsors.equals(advertisers) context TournamentControl::advertiseTournament() pre: tournament.sponsors->isEmpty and not tournament.advertised context TournamentControl::advertiseTournament() post: tournament.advertised context TournamentControl::acceptPlayer(p) pre: tournament.advertised and interestedPlayers->includes(p) and not isPlayerOverbooked(p) context TournamentControl::acceptPlayer(p) post: tournament.players->includes(p) Bernd Bruegge & Allen H. Dutoit Object-Oriented Software Engineering: Using UML, Patterns, and Java 18 Specifying invariants on Tournament and Tournament Control All Matches of in a Tournament must occur within the time frame of the Tournament context Tournament inv: matches->forAll(m| m.start.after(start) and m.start.before(end)) No Player can take part in two or more Tournaments that overlap context TournamentControl inv: tournament.players->forAll(p| p.tournaments->forAll(t| t <> tournament implies not t.overlap(tournament))) Bernd Bruegge & Allen H. Dutoit Object-Oriented Software Engineering: Using UML, Patterns, and Java 19 Specifying invariants on Match Player players * Match players * * tournaments Tournament matches * A match can only involve players who are accepted in the tournament context Match inv: players->forAll(p| p.tournaments->exists(t| t.matches->includes(self))) context Match inv: players.tournaments.matches.includes(self) Bernd Bruegge & Allen H. Dutoit Object-Oriented Software Engineering: Using UML, Patterns, and Java 20 Figure 9-13, A simple example of contract inheritance: An invariant specified in a superclass must hold for all of its subclasses. User email:String «invariant» email <> nil notify() LeagueOwner Bernd Bruegge & Allen H. Dutoit Player Advertiser Object-Oriented Software Engineering: Using UML, Patterns, and Java Spectator 21 Figure 9-14, Embedded ODD approach. Class stubs are generated from the object design model. Analysis Document analysis Analysis model RAD System design Subsystem decomposition Design goals Object design Initial object design model Generate class stubs Initial class stubs Implementation Commented code Bernd Bruegge & Allen H. Dutoit Document object design ODD Object-Oriented Software Engineering: Using UML, Patterns, and Java 22 Figure 9-16, new Round class and changes in the TournamentStyle, Tournament, and Round APIs. League 1 * planRounds(Tournament) :List legalNumPlayers(n:int) :boolean getTournamentStyle() :TournamentStyle * players * TournamentStyle tournaments Player name:String email:String notify(Player,Message) getMatches(Tournament) Tournament name start end acceptPlayer() removePlayer() plan() {ordered} players * Match start status score playMove(Player,Move) getMoves():List Bernd Bruegge & Allen H. Dutoit matches * 1 * Round plan() getPreviousRound():Round isPlanned():boolean isCompleted():boolean Object-Oriented Software Engineering: Using UML, Patterns, and Java 23 Constraints on TournamentStyle Only tournaments without rounds and with the right number of players can be planned. context TournamentStyle::planRounds(t:Tournament) pre: t <> nil and t.rounds = nil and legalNumPlayers(t)->contains(t.players->size) All players are assigned to at least one match context TournamentStyle::planRounds(t:Tournament) post: t.getPlayers()->forAll(p| p.getMatches(tournament)->notEmpty) context TournamentStyle::planRounds(t:Tournament) post: result->forAll(r1,r2| r1<>r2 implies r1.getEndDate().before(r2.getStartDate()) or r1.getStartDate().after(r2.getEndDate()) Bernd Bruegge & Allen H. Dutoit Object-Oriented Software Engineering: Using UML, Patterns, and Java 24 Invariant on Round A player cannot be assigned to more than one match per round context Round inv: matches->forAll(m1:Match| m1.players->forAll(p:Player| p.matches->forAll(m2:Match| m1 <> m2 implies m1.round <> m2.round))) Bernd Bruegge & Allen H. Dutoit Object-Oriented Software Engineering: Using UML, Patterns, and Java 25 Constraints on Round.plan() Invoking plan() on a Round whose previous Round is completed results in a planned Round context Round.plan() post: @pre.getPreviousRound().isCompleted() implies isPlanned() A round is planned if all matches have players assigned to them context Round.isPlanned() post: result implies matches->forAll(m| m.players->size = tournament.league.game.numPlayersPerMatch) A round is completed if all of its matches are completed. context Round.isCompleted() post: result implies matches->forAll(m| m.winner <> nil) Bernd Bruegge & Allen H. Dutoit Object-Oriented Software Engineering: Using UML, Patterns, and Java 26 Constraints on KnockOutStyle The number of players should be a power of two. context KnockOutStyle::legalNumPlayers(t:Tournament) post: result Sequence[2..t.maxNumPlayers]->select(elem| floor(log(elem)/log(2)) = (log(elem)/log(2))) The number of matches in a round is 1 for the last round. Otherwise, the number of matches in a round is exactly twice the number of matches in the subsequent round. context KnockOutStyle::planRounds(t:Tournament) post: result->forAll(index:Integer| if (index = result->size) then result->at(index).matches->size = 1 else result->at(index).matches->size = (2*result->at(index+1).matches->size)) endif) Bernd Bruegge & Allen H. Dutoit Object-Oriented Software Engineering: Using UML, Patterns, and Java 27 Constraints on KnockOutRound A player can play in a round only if it is the first round or if it is the winner of a previous round. context KnockOutRound inv: previousRound = nil or matches.players->forAll(p| round.previousRound.matches->exists(m| m.winner = p)) If the previous round is not completed, this round cannot be planned. context KockOutRound::plan() post: not self@pre.getPreviousRound().isCompleted() implies not isPlanned() Bernd Bruegge & Allen H. Dutoit Object-Oriented Software Engineering: Using UML, Patterns, and Java 28