La brume enveloppait les docks, estompant les contours des grues comme des fantômes métalliques. J’attendais. Pas un contact, non. Une livraison. Un objet. Une entité autonome avec ses données et ses comportements. C’est ça, la POO. On ne pense plus en simples variables et fonctions, mais en agents. Chacun avec son rôle, ses secrets, ses protocoles.
Classes et objets
La classe, c’est le plan. Le schéma directeur. L’objet, c’est l’instance concrète, l’agent sur le terrain.
class Agent:
"""Classe définissant un agent opérationnel."""
pass
# Création d'objets (instances)
ombre = Agent()
silencieux = Agent()
Une classe définit une catégorie d’êtres. Un objet en est une incarnation. ombre et silencieux sont deux agents distincts, mais construits sur le même modèle.
Constructeur (__init__)
C’est la méthode qui s’exécute à la naissance de l’objet. Son baptême. On y initialise ses attributs, son état initial.
class Agent:
def __init__(self, nom_code, specialite, statut="actif"):
self.nom_code = nom_code
self.specialite = specialite
self.statut = statut
self.missions_accomplies = 0
print(f"Agent {nom_code} initialisé. Spécialité: {specialite}")
# Instanciation avec le constructeur
fantome = Agent("Fantôme", "infiltration", "deep_cover")
vega = Agent("Vega", "cyber-intrusion")
Le self est la référence à l’objet lui-même. C’est par lui qu’il se connaît.
Attributs et méthodes
Les attributs sont les données de l’objet. Ses caractéristiques. Les méthodes sont ses actions, ses compétences.
class Agent:
def __init__(self, nom_code, specialite):
self.nom_code = nom_code # Attribut
self.specialite = specialite # Attribut
self._cachette = None # Attribut "protégé" (convention)
# Méthode : une action que l'agent peut effectuer
def accomplir_mission(self, difficulte):
"""Exécute une mission et met à jour le statut."""
print(f"{self.nom_code} exécute une mission (niveau {difficulte}).")
# ... logique de mission ...
self._mettre_a_jour_carnet()
return "succès" if difficulte < 8 else "échec contrôlé"
# Méthode "privée" (par convention)
def _mettre_a_jour_carnet(self):
"""Méthode interne. Ne pas appeler de l'extérieur."""
self.missions_accomplies += 1
# Utilisation
araignee = Agent("Araignée", "réseau")
resultat = araignee.accomplir_mission(5)
print(f"Missions accomplies: {araignee.missions_accomplies}")
L’objet sait des choses (attributs) et sait faire des choses (méthodes). Il est autonome.
Encapsulation
C’est le principe de la boîte noire. On cache l’état interne. On n’expose que ce qui est nécessaire.
class CompteOffshore:
def __init__(self, id, devise="USD"):
self._id = id # "Protégé"
self._devise = devise
self.__solde = 0 # "Privé" (name mangling)
self.__code_acces = self._generer_code()
def deposer(self, montant):
"""Interface publique pour déposer."""
if montant > 0:
self.__solde += montant
self.__logger(f"Dépôt: {montant} {self._devise}")
return self.__solde
def _generer_code(self): # Méthode "protégée"
import random
return random.randint(10000, 99999)
def __logger(self, message): # Méthode "privée"
# Log interne, invisible de l'extérieur
with open(f"log_{self._id}.txt", "a") as f:
f.write(message + "\n")
# Utilisation
compte_x = CompteOffshore("X9")
compte_x.deposer(50000)
# compte_x.__solde # ERREUR : attribut privé, inaccessible.
# compte_x._generer_code() # Possible, mais contre la convention.
L’encapsulation protège l’intégrité de l’objet. On ne laisse pas n’importe qui tripoter le solde du compte.
Héritage
Créer une classe enfant qui hérite des caractéristiques d’une classe parent, et qui peut les spécialiser.
class Agent: # Classe parent
def __init__(self, nom_code):
self.nom_code = nom_code
self.estime = 10
def rapporter(self, information):
print(f"[{self.nom_code}] Rapporte: {information}")
class Infiltre(Agent): # Classe enfant
def __init__(self, nom_code, couverture):
super().__init__(nom_code) # Appel du constructeur parent
self.couverture = couverture
self.penetration = 0
# Surcharge de méthode (spécialisation)
def rapporter(self, information, urgence=False):
super().rapporter(information) # Appel de la méthode parent
if urgence:
print(f" -> Message prioritaire, extraction recommandée.")
self.penetration += 1
# Utilisation
camaleon = Infiltre("Caméléon", "journaliste")
camaleon.rapporter("Le ministre a un compte en Suisse.", urgence=True)
print(f"Estime: {camaleon.estime}, Pénétration: {camaleon.penetration}")
L’héritage, c’est la transmission du savoir-faire. L’enfant a tout du parent, mais il peut faire plus, ou différemment.
Polymorphisme
Le même nom d’action, des comportements différents selon l’objet.
class Saboteur:
def neutraliser(self):
print("Désactive les systèmes physiques.")
class Hacker:
def neutraliser(self):
print("Corrompt les données et efface les logs.")
class Persuadeur:
def neutraliser(self):
print("Convainc la cible de se retirer.")
# Fonction qui utilise le polymorphisme
def executer_operation_nette(agent):
"""Prend n'importe quel agent ayant une méthode 'neutraliser'."""
agent.neutraliser()
# Utilisation
equipe = [Saboteur(), Hacker(), Persuadeur()]
for agent in equipe:
executer_operation_nette(agent) # Chaque agent réagit à sa façon.
Le polymorphisme, c’est l’interchangeabilité. Vous donnez un ordre standard (neutraliser), et chaque type d’agent l’exécute avec ses moyens propres. Vous n’avez pas besoin de connaître les détails, seulement l’interface.
La silhouette est enfin apparue dans la brume. Un objet Courier, avec ses attributs (colis_scellé, itineraire_verrouillé) et ses méthodes (livrer(), confirmer_reception()). Il a accompli sa tâche sans que j’aie à savoir comment il avait traversé la ville. C’était un objet fiable, encapsulé, qui faisait son travail.
La POO, c’est modéliser le monde comme un réseau d’agents interactifs, chacun avec ses responsabilités, ses secrets, ses compétences. C’est la façon de penser des architectes. Des stratèges.
Et dans notre jeu, penser en objets, c’est rester en vie.
Le monde est un réseau d'objets. Soyez-en le maître.