Problématique
La programmation orientée objet s’attache à représenter fidèlement les entités du monde réel. Or, ces entités forment des ensembles, des collections et ne sont pas isolées. Une tâche fondamentale consiste donc à gérer des collections d’objets, et à permettre à un objet d’accéder aux objets auxquels il est lié.
L’objectif de cette activité consiste à travailler :
- la gestion des collections (tableaux) d’objets : parcours, ajout, recherche,
- l’accès aux attributs d’un objet,
- l’accès aux objets associés (navigation).
Ce type d’exercice est caractéristique des sujets d’examens évaluant les compétences de base en programmation orientée objets.
Exemple
L’exemple retenu est celui d’une classe Organisation et d’une classe Stage.
Une organisation peut avoir proposé plusieurs stages, mais un stage a eu lieu
dans une seule organisation. L’objectif est d’écrire une application permettant :
- d’afficher la liste des organisations ;
- d’afficher la liste des stages d’une organisation ;
- d’afficher la liste des stages, avec pour chacun d’eux l’organisation d’accueil ;
- d’ajouter un stage ;
- de rechercher un stage.
La classe Stage
Un objet de la classe Stage à un trois attributs : l’année de réalisation,
le sujet et l’organisation ou il s’est déroulé :
from __future__ import annotations
import organisation
class Stage:
_annee: int
_sujet: str
_organisation : Organisation
def __init__(self, annee: int, sujet: str, org: Organisation):
#A COMPLETER
def getAnnee(self) -> int:
return self._annee
def getSujet(self) -> str:
return self._sujet
def getOrganisation(self) -> Organisation:
#A COMPLETER
La classe Organisation
LA classe Organisation représente une entité qui peut proposer plusieurs
stages. Elle contient des informations propres à l’organisation (le nom et
la ville) ainsi que les stages, tableau d’objets de la classe Stage.
from __future__ import annotations
from typing import List
import stage
class Organisation:
_nom: str
_ville: str
_stages: List[Stage]
def __init__(self, nom: str, ville: str):
self._nom = nom
self._ville = ville
self._stages = []
def getNom(self) -> str:
return self._nom
def getVille(self) -> str:
return self._ville
def getStages(self) -> List[Stage]:
#A COMPLETER
def ajoutStage(self, stg: Stage) -> None:
#A COMPLETER
Initialisation des données
Le programme principal comprend une fonction initialiser_donnees qui, pour
cette version, crée un jeu d’essai :
from __future__ import annotations
from typing import List
from stage import Stage
from organisation import Organisation
def initialiser_donnees(organisations: List[Organisation], stages: List[Stages]) -> None:
"""
Initialise la liste des organisation et des stages
@param organisations la liste des organisations, en entrée-sortie
@param stages la liste des stages, en entrée-sortie
"""
orga_cps = Organisation("CPS", "Papeete")
orga_logis = Organisation("Logis", "Faa'a")
orga_mairie = Organisation("Mairie d'Arue", "Arue")
orga_opt = Organisation("OPT", "Pirae")
orga_proxi = Organisation("Prox-i", "Papeete")
organisations.extend([ orga_cps, orga_logis, orga_mairie, orga_opt, orga_proxi ])
stage_dev_web = Stage(2024, "Développement d'un site web", orga_cps)
orga_cps.ajoutStage(stage_dev_web)
stage_api_python = Stage(2024, "Création d'une API en Python", orga_logis)
stage_maintenance = Stage(2023, "Maintenance d'une application Java", orga_logis)
orga_logis.ajoutStage(stage_api_python)
orga_logis.ajoutStage(stage_maintenance)
stage_intranet = Stage(2024, "Refonte de l'intranet", orga_mairie)
orga_mairie.ajoutStage(stage_intranet)
stage_data = Stage(2024, "Analyse de données client", orga_opt)
orga_opt.ajoutStage(stage_data)
stage_workflow = Stage(2025, "Gestion des flux de travail", orga_proxi)
stage_lowcode = Stage(2024, "Création d'une application Low-Code", orga_proxi)
orga_proxi.ajoutStage(stage_workflow)
orga_proxi.ajoutStage(stage_lowcode)
stages.extend([ stage_api_python, stage_data, stage_dev_web, stage_intranet, stage_maintenance, stage_workflow, stage_lowcode ])
Travail à faire : compléter le jeu d’essai en y ajoutant deux autres stages de votre convenance.
Approfondissement :
- Insérer les stages et organisations dans une base de données (SQLite par exemple) ; remarque : une IA peut aisément transformer le code Pythob en instructions SQL.
- Charger les données depuis la base de données ; cf documentation Python/SQLite.
Le menu
L’application, en mode console, comprend la fonction utilitaire menu permettant
à l’utilisateur de sélectionner l’opération à réaliser :
def menu(choix : List[str]) -> int:
print("")
for i in range(len(choix)) :
print(i,":",choix[i])
reponse = int (input("votre choix : "))
print("")
return reponse
L’affichage de la liste des organisations
Objectif pédagogique: parcours de collection.
Cette fonction a pour rôle de présenter à l’utilisateur la liste des organisations
disponibles. Elle reçoit en paramètre un tableau d’objets Organisation et
doit parcourir cette collection pour afficher les informations essentielles
de chaque organisation (son nom et sa ville). L’objectif est de fournir un
affichage clair et numéroté pour que l’utilisateur puisse ensuite sélectionner
une organisation par son numéro.
Exemple d’affichage attendu :
Liste des organisations :
1 : CPS, Papeete
2 : Logis, Faa'a
3 : Mairie d'Arue, Arue
4 : OPT, Pirae
5 : Prox-i, Papeete
Profil et spécification de la fonction :
def afficher_organisations(organisations: List[Organisation]):
"""
Affiche la liste des organisations.
@param organisations la liste des organisations
"""
#A COMPLETER: pour chaque organisation, afficher son nom et sa ville
L’affichage de la liste des stages
Objectif pédagogique : navigation d’un objet à un autre objet associé.
Cette fonction reçoit une liste de stages et doit afficher, pour chaque stage,
son année, son sujet, ainsi que le nom de l’organisation qui l’accueille.
Pour obtenir ce dernier élément, il est nécessaire de “naviguer” de l’objet
de la classe Stage vers l’objet Organisation auquel il est lié.
Concrètement, pour chaque stage de la liste, il faut :
- utiliser l’accesseur
getOrganisation()pour obtenir l’objet de la classeOrganisationcorrespondant au lieu du stage ; - une fois cette organisation obtenue, il faut utiliser sa méthode
getNom().
def afficher_stages(stages: List[Stage]):
"""
Affiche la liste des stages avec le nom de l'organisation.
@param stages la liste des stages à afficher
"""
#A COMPLETER: pour chaque stage, afficher son année, son sujet
#ainsi que le nom de l'organisation
L’ajout d’un stage
Cette fonction permet d’enrichir le jeu de données en créant une nouvelle
instance de Stage. Elle reçoit en paramètres toutes les informations nécessaires
à cette opération (la liste des stages, l’organisation, l’année et le sujet).
Le travail consiste à :
- Créer une nouvelle instance de la classe
Stageà partir des paramètres. - Ajouter ce stage aux stages de l’organisation concernée (cf
ajoutStage()) - Ajouter ce nouvel objet à la liste des stages.
def ajouter_stage(stages: List[Stage], org: Organisation, annee: int, sujet: str):
"""
Instancie et ajoute un stage à une organisation et à la liste des stages.
@param stages la liste des stages
@param org l'organisation du stage
@param annee l'année du stage
@param sujet le sujet du stage
"""
#A COMPLETER: instancier un nouveau stage,
#l'ajouter à l'organisation et à la liste des stages.
Remarque : au niveau de la conception, on aurait pu imaginer, que c’est le
constructeur de la classe Stage qui appelle lui même la méthode ajoutStage :
org.ajoutStage(self).
La recherche de stage
Objectif pédagogique : réviser la recherche séquentielle.
L’objectif de cette fonction est de retourner une nouvelle liste ne contenant que les stages qui correspondent au terme de recherche passé en paramètre (soit l’année, soit un partie de texte du sujet). La stratégie est la suivante :
Pour chaque stage, l’ajouter à la sélection s’il correspond au terme de recherche : - le terme correspond à l’année du stage (attention aux types) ; - ou le terme recherché apparaît dans le sujet du stage.
def rechercher_stage(stages: List[Stage], terme: str) -> List[Stage]:
"""
Recherche des stages par année ou par sujet.
@param stages la liste des stages à filtrer
@param terme le terme de recherche (année ou partie du sujet)
@return la liste des stages correspondants au terme de recherche
"""
selection: List[Stage] = []
#A COMPLETER : Implémenter la stratégie de recherche décrite ci-dessus
return selection
Le point d’entrée
Voici le point d’entrée du programme, à compléter :
if __name__ == "__main__":
organisations: List[Organisation] = []
stages: List[Stage] = []
initialiser_donnees(organisations, stages)
choix = -1
while choix != 0:
choix = menu(["Quitter", "Liste des organisations", "Stages d'une organisation", "Liste des stages", "Ajouter un stage", "Rechercher un stage"])
if choix == 1:
afficher_organisations(organisations)
elif choix == 2:
afficher_organisations(organisations)
num = int (input("n° de l'organisation : "))
if num > 0 and num <= len(organisations):
#A COMPLETER
elif choix == 3:
afficher_stages(stages)
elif choix == 4:
afficher_organisations(organisations)
num = int (input("n° de l'organisation : "))
if num > 0 and num <= len(organisations):
annee = int(input("Année du stage : "))
sujet = input("Sujet du stage : ")
#A COMPLETER
elif choix == 5:
terme = input("Terme recherché : ")
#A COMPLETER