L’objectif de cette séance est de vous faire pratiquer l’identification des classes que peuvent constituer un logiciel objet qui répond à un problème donné en utilisant quelques exercices simples.
Important
Pour cette séance vous n’allez pas écrire du code, vous allez réfléchir à comment structurer une solution à un problème donné et vous donnerez le pseudo-code correspondant. Vous n’avez donc pas besoin d’utiliser votre ordinateur, un simple papier/crayon suffit.
Contenu de l’activité
Pour chaque exercice vous devez identifier les objets, les classes, les méthodes, les attributs, les associations et les relations d’héritage (voir tableau 1). Pour un objet, donnez sa classe ; pour une classe, donnez ses attributs et méthodes ; pour une méthode, donnez ses arguments et, si besoin, son résultat ; pour un attribut, donnez son type et pour une association précisez les classes qu’elle met en relation.
Tableau 1. Classes, objets, attributs, méthodes et associations.
Mage, guerrier, voleur
L’objectif de cet exercice est de documenter, sous la forme de tableau les différents éléments qui rentrent en jeu dans une version objet du jeu mage, guerrier, voleur qui a été introduit pendant le cours.
Pour rappel, les règles du jeu sont les suivantes : on souhaite programmer, en pseudo-code, un jeu de rôle de combat. Dans le jeu on a trois types de personnages : le mage, le guerrier et le voleur. Ils ont tous des points de vie au départ (hp), causent des dégâts à ses opposants (damage) et ont un personnage qui leur cause 2 fois plus de dégâts (weakness). Plus précisément :
De plus, à chaque victoire, un personnage gagne en expérience et ces gains sont différents selon le personnage :
Mage : +5 hp ; +1 damage
Guerrier : +10 hp; +2 damage
Voleur : +8 hp; +1 damage
Une partie se déroule de la manière suivante : à chaque tour, l’attaquant et la cible sont choisis de manière aléatoire. Après l’attaque, les dégâts infligés à la cible sont calculés : la puissance d’attaque de l’attaquant ou 2 fois cette puissance si l’attaquant est le point faible de la cible. La partie est finie quand il ne reste qu’un seul survivant. Enfin, le mage n’est vaincu que lorsque ses points de vie sont <= -5
Jeu sans héritage
À faire
Complétez le tableau pour la version du jeu sans héritage.
Correction
Cliquez ici pour afficher la correction.
Le point à ne pas manquer est d’indiquer le type des attributs comme des méthodes. C’est lui qui dit quelles opérations sont possibles :
le type des paramètres d’une méthode. Ex. dans la méthode attack() on met le type du paramètre et pas son nom. C’est cette information qui est importante pour pouvoir ensuite donner le code (ou pseudo-code) de la méthode ;
le type du résultat rendu par la méthode. Ex. dans la méthode is_alive() on dit que c’est un booléen qui est rendu par la méthode ;
le type des attributs, qui donne des indications du type d’opérations qu’il sera possible de réaliser sur l’attribut. Par ex. il sera possible d’ajouter des points de vie à un personnage mais il n’est pas possible de faire ce type d’opérations sur son nom.
Tableau 2. Mage-Guerrier-Voleur sans héritage.
Jeu avec héritage
À faire
Complétez le tableau pour la version du jeu avec héritage.
Correction
Cliquez ici pour afficher la correction.
Deux versions sont données ici, chacune avec ses avantages et ses inconvénients. Dans la première, rien ne distingue un mage, un guerrier et un voleur : il n’y a que des personnages. Dans la seconde, chaque type a sa classe, mais on ne pourra pas en ajouter si les règles du jeu changent : c’est moins flexible. Le choix entre les deux dépend du dialogue avec le client et de ce qu’il veut, tel qu’il ressort de l’énoncé du problème.
Tableau 3a. Mage-Guerrier-Voleur avec héritage.
Tableau 3b. Mage-Guerrier-Voleur avec héritage.
L’ascenseur
On souhaite modéliser le fonctionnement (simplifié) d’un ascenseur. L’ascenseur ferme ses portes avant de se déplacer vers un autre étage. De plus, l’ascenseur connaît tous les déplacements d’un étage à un autre effectués depuis sa mise en service.
Identification des éléments
À faire
Complétez le tableau avec les éléments qui permettent de répondre à l’énoncé.
Correction
Cliquez ici pour afficher la correction.
Deux solutions sont proposées ici. La différence dans les deux solutions proposées est l’identification de la classe Floor. La question de la garder se pose puisqu’elle se résume à un entier et aucune méthode n’y est attachée. Si un étage (tel que vu par le système d’ascenseur) ne présente aucune autre caractéristique que celles associées à son numéro d’étage, vous n’aurez peut-être pas besoin d’une classe Floor distincte. Si, toutefois, les étages ont des propriétés autres que celles de leurs numéros, alors une classe Floor sera appropriée. Par exemple, certains étages peuvent avoir des droits d’accès spéciaux définissant qui peut les visiter ; dans ce cas, la classe Floor pourrait inclure une caractéristique telle que rights:[Authorization]. Ou alors si le système est conçu pour un cabinet d’architectes, la classe Floor pourrait avoir d’autres caractéristiques comme la surface…
Et quel est l’intérêt de la classe Move ? Un déplacement peut être représenté par un dictionnaire et l’historique serait alors une liste de dictionnaires. Comme le problème est simple, effectivement c’est envisageable et dans ce cas on rentre dans le cas de la programmation procédurale (au détail près de la classe Elevator). Mais du point de vue du problème posé et pour aboutir à une solution OO, la notion de déplacement est une élément fondamental du système d’ascenseur et donc, elle est réifiée par cette classe.
Tableau 4a. Déplacement d’un ascenseur avec classe Floor.
Tableau 4b. Déplacement d’un ascenseur avec sans classe Floor.
Pseudo-code
À faire
Donnez le pseudo code qui correspond à la création d’un ascenseur, la fermeture de ses portes et son déplacement au 4ème étage.
On souhaite créer un système très simple de gestion de comptes bancaires. Le système (logiciel) doit permettre de gérer les comptes bancaires des clients (en ajouter, supprimer, modifier les informations associées) et les transactions (créditer/débiter un compte et connaître l’historique des transactions faites sur un compte) qui y sont faites pour une institution bancaire.
Identification des éléments
À faire
Complétez le tableau avec les éléments qui permettent de répondre à l’énoncé.
Correction
Cliquez ici pour afficher la correction.
Tableau 5. Logiciel de gestion de comptes bancaires.
Pseudo-code instanciation
À faire
Donnez le pseudo-code qui crée la banque cmb, ouvre un compte pour Louis Dupond et crédite 100 euros sur ce compte.
Correction
Cliquez ici pour afficher la correction.
# Create the bankcmb = Bank("Credit Mutuel")
# Create the clientclient1 = Client("Dupond", "Louis")
# Open a new account in the bank for the clientcompte1 = cmb.open_account(client1)
# Credit some euros into the new accountcmb.credit(compte1, 100)
Pseudo-code constructeur
À faire
Donnez le pseudo-code du constructeur de la classe Bank et de la méthode open_account.
Correction
Cliquez ici pour afficher la correction.
CLASS Bank() :
# Attributes of the class PRIVATE ATTRIBUTE name: str
PRIVATE ATTRIBUTE accounts: [Account]
# The constructor initializes attributs CONSTRUCT Bank(name: str) :
self.name = name
self.accounts = []
# Open an account = create the new account and# add it to the list of accounts of the bank METHOD open_account(client: Client) -> Account:
account = Account(client)
self.accounts.append(account)
return account
Pseudo-code classe BankAccount
À faire
Donnez le pseudo-code de la classe BankAccount.
Correction
Cliquez ici pour afficher la correction.
CLASS Account:
# Attributes of the class PRIVATE ATTRIBUTE client: Client
PRIVATE ATTRIBUTE balance: float
PRIVATE ATTRIBUTE transactions: [Transaction]
# The constructor initializes attributs CONSTRUCT Account(client: Client) :
self.client = client
self.balance =0 self.transactions = []
# Compute the new balance and# add the transaction to the list of transactions of the account METHOD credit(amount: float) -> float:
self.balance += amount
tx1 = Transaction(now, montant, "CREDIT")
self.transactions.append(tx1)
return self.balance
# Compute the new balance and# add the transaction to the list of transactions of the account METHOD debit(amount: float) -> float:
if self.balance - amount >0 :
self.balance -= amount
tx1 = Transaction(now, amount, "DEBIT")
self.transactions.append(tx1)
return self.balance
Version avec contrôle du montant passé en paramètre.
CLASS Account:
# Attributes of the class PRIVATE ATTRIBUTE client: Client
PRIVATE ATTRIBUTE balance: float
PRIVATE ATTRIBUTE transactions: [Transaction]
# The constructor initializes attributs CONSTRUCT Account(client: Client) :
self.client = client
self.balance =0 self.transactions = []
# Compute the new balance and# add the transaction to the list of transactions of the account METHOD credit(amount: float) -> float:
if amount >0:
self.balance += montant
tx1 = Transaction(now, montant, "CREDIT")
self.transactions.append(tx1)
return self.balance
# Compute the new balance and# add the transaction to the list of transactions of the account METHOD debit(amount: float) -> float :
if amount >0:
if self.balance - amount >0 :
self.balance -= amount
tx1 = Transaction(now, amount, "DEBIT")
self.transactions.append(tx1)
return self.balance
Nouveaux types de comptes
À faire
On souhaite maintenant qu’une banque puisse gérer des comptes jeunes, qui, au démarrage ont un solde de 500 euros et pour lesquels il n’est plus possible de débiter de l’argent 10 ans après leur ouverture. Modifiez le tableau construit dans les questions précédentes pour tenir compte de cette contrainte.
Correction
Cliquez ici pour afficher la correction.
Tableau 5. Logiciel de gestion de comptes bancaires avec comptes jeune.
Pseudo-code gestion des types de comptes
À faire
Donnez le pseudo-code des modifications apportées.
Correction
Cliquez ici pour afficher la correction.
CLASS YoungAccount(Account) :
PRIVATE ATTRIBUTE opened: Date
CONSTRUCT YoungAccount(client: Client) :
self.client = client
self.balance =500 self.opened = now
self.transactions = []
METHOD debit(amount: float) -> float:
if now < self.opened +10 :
if self.balance - amount >0 :
self.balance -= amount
tx1 = Transaction(now, amount, "DEBIT")
self.transactions.append(tx1)
return self.balance
CLASS Bank() :
METHOD open_young_account(client: Client) --> YoungAccount :
account = YoungAccount(client)
self.accounts.append(account)
return account
Pour aller plus loin
Parcours de soins dans un hôpital
On veut développer un logiciel pour informatiser le parcours de soins dans un hôpital. Dans le logiciel, on doit avoir le nom, prénom, date de naissance, sexe et actes médicaux que les patients ont subis. Ces actes peuvent être des diagnostics ou des soins. Les deux sont réalisés par un personnel soignant à une certaine date. Mais un soin produit une certaine amélioration de l’état du patient (en pourcentage) et un diagnostic a une certaine validité (fiabilité du diagnostic en pourcentage).
Identification des éléments
À faire
Complétez le tableau avec les éléments qui permettent de répondre à l’énoncé.
Correction
Cliquez ici pour afficher la correction.
Tableau 5. Logiciel de gestion des actes médicales d’un hôpital.
Pseudo-code instanciation
À faire
Donnez le pseudo-code qui crée l’hôpital Cavale Blanche, crée le dossier médical de Louis Dupond né à Valence et qui a été diagnostiqué le 08/07/2025 comme ayant (à 90% de chances) un Zona.
Correction
Cliquez ici pour afficher la correction.
# Create the hospitalcavale = Hospital("Cavale Blanche")
# Create the patientpatient1 = cavale.new_patient("Dupond", "Louis", Date("2002-12-10"), "Male")
# Create the medical actmedical_act = Diagnose(Date("2025/07/08"), "Mme Sabre", "Zona", 90)
cavale.new_medical_act(patient1, medical_act)
Pseudo-code classes
À faire
Donnez le pseudo-code des différentes classes identifiées.