Newer
Older
Découpage de la solution en composants (ou sous-systèmes), affectation des responsabilités aux composants et spécification des interfaces fournies et requises par ces composants
Moyens::
Utilisez des diagrammes d'interaction (séquence, communication) pour décrire l'échange de messages entre les composants pour en déduire leurs interfaces.
.Diagramme de composants décrivant la solution proposée
== Game Board Component (Composant Plateau de Jeu)
component "Game Board Component" as GameBoard {
interface "BoardLayoutInterface" as BoardLayout
interface "SpecialEventInterface" as SpecialEvent
....
TIP: Si nécessaire, utilisez le langage OCL pour spécifier les pré et post-conditions des opérations.
.Contraintes sur les operations
[source, ocl]
----
context A::operationA(a: String, b: Integer): Boolean
pre: a.size() > 3
post:
-- Pas de postconditions
----
GameBoard -up- BoardLayout
GameBoard -down- SpecialEvent
. Initialisation du Plateau de Jeu :
* Crée et initialise la représentation du plateau de jeu avec toutes les cases et pions des joueurs.
. Gestion des Connexions au Plateau :
* Gère les connexions des joueurs au plateau de jeu et attribue les pions de manière unique.
. Début de la Partie :
* Lance la partie une fois que tous les joueurs sont prêts et distribue les éléments nécessaires pour débuter, comme les cartes de départ.
. Gestion des Tours
* À chaque tour, gère la réception des choix des joueurs, y compris les cartes jouées et les actions entreprises.
. Distribution des Mises à Jour de Jeu :
* Après chaque tour, envoie aux joueurs les mises à jour nécessaires, telles que de nouvelles cartes et les actions des autres joueurs.
. Détermination du Gagnant :
* À la fin de la partie, évalue les conditions de victoire pour déterminer le gagnant.
left to right direction
skinparam packageStyle rectangle
component "Game Board Component" as GameBoard {
interface "BoardLayoutInterface" as BoardLayout
interface "SpecialEventInterface" as SpecialEvent
}
....
.Contraintes sur les operations
[source, ocl]
----
context B::operationA(a: String, b: Integer): Boolean
pre: a.size() > 3
post:
-- Pas de postconditions
----
== Composant A
[note]
====
Description de ses responsabilités et de ses interfaces
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
GameBoard -up- BoardLayout
GameBoard -down- SpecialEvent
....
. initializeGameBoard() : GameBoardState
* Description : Initialise le plateau de jeu pour la nouvelle partie.
* Aucun paramètre.
* Retour : `GameBoardState` - État initial du plateau de jeu.
. connectPlayer(playerId: String[1..1], playerToken: Token[1..1]) : Boolean
* Description : Connecte un joueur au jeu et lui attribue un pion.
* Paramètres : `playerId` - L'identifiant unique du joueur, playerToken - Le pion attribué au joueur.
* Retour : `Boolean` - Succès ou échec de la connexion.
. startGame() : GameStartOutcome
* Description : Démarre la partie une fois tous les joueurs connectés.
* Aucun paramètre.
* Retour : `GameStartOutcome` - Détails sur le démarrage de la partie, y compris l'ordre des joueurs
. receiveTurnActions(actions: List<Action>[1..*]) : TurnOutcome
* Description : Reçoit et traite les actions des joueurs pour un tour.
* Paramètres : actions - Liste des actions entreprises par les joueurs pendant leur tour.
* Retour : `TurnOutcome` - Résultat du traitement des actions du tour.
. endGame() : GameEndOutcome
* Description : Termine la partie et détermine le gagnant.
* Aucun paramètre.
* Retour : GameEndOutcome - Résultat de la partie, y compris le gagnant et les scores finaux.
=== Contraintes OCL pour BoardInterface
[ocl]
----
context BoardInterface::connectPlayer(playerId: String, playerToken: Token): Boolean
pre: -- Le joueur n'est pas déjà connecté.
not GameBoard.allInstances().players->exists(p | p.id = playerId)
post: -- Si la méthode retourne vrai, alors le joueur est ajouté à la liste des joueurs du plateau de jeu avec le pion spécifié.
result = true implies (GameBoard.allInstances().players->any(p | p.id = playerId).token = playerToken)
----
== Question Categories Component (Composant Catégories de Questions)
[plantuml, filename="diagramme-questioncategories", format="png"]
....
left to right direction
skinparam packageStyle rectangle
component "Question Categories Component" as QuestionCategories {
interface "CategoryInterface" as CategoryInt
}
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
QuestionCategories -up- CategoryInt
....
=== Responsabilités du Question Categories Component
* Gestion des Catégories :
** Maintient une liste de catégories de questions disponibles dans le jeu.
* Distribution des Questions :
** Fournit des questions à d'autres composants en fonction de la catégorie demandée.
* Mise à jour des Catégories :
** Permet l'ajout de nouvelles catégories ou la modification des catégories existantes.
=== Interfaces fournies
==== CategoryInterface
. getCategories() : List<Category>
** Description : Récupère une liste de toutes les catégories de questions disponibles.
** Aucun paramètre.
** Retour : `List<Category>` - Liste des catégories de questions.
. getQuestionsByCategory(categoryId: String[1]) : List<Question>
** Description : Récupère les questions pour une catégorie de questions spécifique.
** Paramètres : `categoryId` - L'identifiant unique de la catégorie de questions.
** Retour : `List<Question>` - Liste des questions associées à la catégorie spécifiée.
. addCategory(category: Category) : Boolean
** Description : Ajoute une nouvelle catégorie de questions au système.
** Paramètres : `category` - L'objet catégorie à ajouter.
** Retour : `Boolean` - Indique si la catégorie a été ajoutée avec succès.
. updateCategory(categoryId: String[1], newDetails: Category) : Boolean
** Description : Met à jour les détails d'une catégorie de questions existante.
** Paramètres :
*** `categoryId` - L'identifiant unique de la catégorie à mettre à jour.
*** `newDetails` - Les nouveaux détails de la catégorie.
** Retour : `Boolean` - Succès ou échec de la mise à jour.
=== Contraintes OCL pour CategoryInterface
[ocl]
----
context CategoryInterface::getQuestionsByCategory(categoryId: String): List<Question>
pre: -- La catégorie demandée doit exister.
QuestionCategories.allInstances().categories->exists(c | c.id = categoryId)
post: -- Le résultat doit être une liste de questions qui appartient uniquement à la catégorie spécifiée.
result = QuestionCategories.allInstances().categories->select(c | c.id = categoryId).questions
context CategoryInterface::addCategory(category: Category): Boolean
pre: -- La catégorie ne doit pas déjà exister.
not QuestionCategories.allInstances().categories->exists(c | c.id = category.id)
post: -- Si la méthode retourne vrai, alors la nouvelle catégorie est ajoutée.
result = true implies (QuestionCategories.allInstances().categories->includes(category))
----
[WARNING]
====
* La syntaxe de la notation UML est différente de celle de Java{nbsp}!
* Les types de base sont différents aussi{nbsp}! Par exemple, `int`, `float`, `bool` ne sont pas des types UML.
* Si les paramètres sont multivalués (par ex. ensemble, séquence, etc.) utilisez les cardinalités: `names : String [1..4]`
* `List<>`, `Set<>`, etc. ne sont pas des types UML.
====
[plantuml]
....
interface A {
operationA(a: String, b: Integer): Boolean
....
TIP: Si nécessaire, utilisez le langage OCL pour spécifier les pré et post-conditions des opérations.
.Contraintes sur les operations
[source, ocl]
----
context A::operationA(a: String, b: Integer): Boolean
pre: a.size() > 3
post:
-- Pas de postconditions
----
==== Interface B
....
interface B {
operationB(a: String, b: Integer): Boolean
....
.Contraintes sur les operations
[source, ocl]
----
context B::operationA(a: String, b: Integer): Boolean
pre: a.size() > 3
post:
-- Pas de postconditions
----
[note]
====
Description de ses responsabilités et de ses interfaces
====
=== Interface C
[plantuml]
....
interface GameServer {
connect(pseudo: String, password: String, ip: String, port: Integer):Boolean
createGame(numberOfPlayers : Integer): Integer
join(gameId : Integer): Integer
notifyPlayersReady(): String
chooseRole(role: String, playerId: Integer)
resist(numberOfPawns: Integer)
playPlaceCard(playerId: Integer, cardName: String)
playHuntCard(cardName: String)
letGo()
putToken(tokenName: String, cardNames: String [0..2])
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
....
== Interactions
[TIP]
====
* Utilisez les diagrammes d'interaction de la notation UML pour valider les interfaces des composants.
* Basez-vous sur les cas d'utilisation (spécification des exigences) pour illustrer les interactions entre les différents composants
====
[WARNING]
====
* En UML, les interactions se passent au niveau des instances.
* Rappel:
** Niveau classes: Classes, opérations, types, etc.
** Niveau instances: Objets, appels d'opération, valeurs, etc.
====
.Connexion au serveur
[plantuml]
....
@startuml
actor "ClientA:Client" as C1
actor "ClientB:Client" as C2
actor "ClientC:Client" as C3
C1 -> Serveur: Connect("Teddy")
Serveur --> C1 : true
C1 -> Serveur: allPlayers()
Serveur --> C1: {}
C2 -> Serveur: Connect("Romain")
Serveur --> C2 : true
C2 -> Serveur : allPlayers()
Serveur --> C2 : {"Teddy": false}
Serveur --> C1 : newPlayer("Romain")
C3 -> Serveur: Connect("Romain")
Serveur --> C3 : true
Serveur --> C3 : changePseudo("Romain0")
C3 --> Serveur : allPlayers()
Serveur --> C3 : {"Teddy": false, "Romain": false}
Serveur --> C1 : newPlayer("Romain0")
Serveur --> C2 : newPlayer("Romain0")
C1 -> Serveur: ready("Teddy")
Serveur -> C2 : playerReady("Teddy")
Serveur -> C3 : playerReady("Teddy")
C2 -> Serveur: ready("Romain")
Serveur -> C1 : playerReady("Romain")
Serveur -> C3 : playerReady("Romain")
C3 -> Serveur: ready("Romain0")
Serveur -> C1 : playerReady("Romain0")
Serveur -> C2 : playerReady("Romain0")
Serveur -> C1 : play()
Serveur -> C2 : play()
Serveur -> C3 : play()
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
....
.Déroulement de l'initialisation du tour 1
[plantuml]
....
@startuml
actor "ClientA:Client" as C1
actor "ClientB:Client" as C2
actor "ClientC:Client" as C3
@enduml
....
.Déroulement d'un tour (on suppose les clients déjà initialisés et le tour 4)
[plantuml]
....
@startuml
actor "Rom:Client" as C1
actor "Ted:Client" as C2
actor "Isma:Client" as C3
@enduml
....
.Rejoindre une partie
[plantuml]
....
participant "__one:Player__" as player1
participant "__two:Player__" as player2
participant "__three:Player__" as player3
participant "__four:Player__" as player4
participant "__five:Player__" as player5
participant "__six:Player__" as player6
participant "__game:GameServer__" as game
player1 -> game : id := createGame(6)
par
player1 ->> game : playerId := join(id, one)
player2 ->> game : playerId := join(id, two)
player3 ->> game : playerId := join(id, three)
player4 ->> game : playerId := join(id, four)
player5 ->> game : playerId := join(id, five)
player6 ->> game : playerId := join(id, six)
end
game --> player1: notifyPlayersReady()
player1 -> game: role := chooseRole("Creature", two)
par
game --> player1: gameStart(boardGameState)
game --> player2: gameStart(boardGameState)
game --> player3: gameStart(boardGameState)
game --> player4: gameStart(boardGameState)
game --> player5: gameStart(boardGameState)
game --> player6: gameStart(boardGameState)
end
....