Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Concepts

On va passer en revue les concepts importants de la programmation objet. C’est un catalogue… bonne nuit !

Classe et objet

Une classe est un type. Elle est généralement définie par une structure avec des attributs/champs et des méthodes (fonctions).


Integer (entier) est une classe.


Un objet est une instance, une donnée qui instancie une classe.


Des objets/intances sont : 0, 1, 2, 3, etc. Ils instancient la classe Integer.

En Python on définit une classe cela :

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def norm():
        return sqrt(self.x ** 2 + self.y ** 2)

p = Point(2, 3)
q = Point(0, 1)
print(p.norm())

Point est une classe. p et q sont des objets.

Constructeur

  • En Python, la méthode __init__ est le constructeur. Il explique comment construire un objet. Il n’y a qu’un seul constructeur en Python.
  • En C++, Java, il peut y avoir plusieurs constructeurs qui s’appelle tous avec le nom de la classe.
  • En Rust, les constructeurs s’appellent comme on veut.

Héritage

L’héritage est la relation est-un. Par exemple, un chat est un animal.

class Animal():
    pass

class Cat(Animal):
    def speak(self):
        print("miaou")
  • Un gobelin est un enemi.
  • Un entier est un nombre.

Une classe A hérite de B si tout objet A est un B.

class Animal():
    pass

class Cat(Animal):
    def speak(self):
        print("miaou")
  • En Python on peut tester qu’une classe class1 hérite de class2 avec issubclass(class1, class2).

La hiérarchie de classes des nombres en Python est donnée ici : (https://peps.python.org/pep-3141/)[https://peps.python.org/pep-3141/].

Encapsulation

L’encapsulation consiste à s’assurer que certaines parties techniques (champs ou méthodes) d’une classe ne soient pas utilisées ailleurs que dans la classe. Il y a des degrés d’encapsulation. On prend ici la convention Java pour en parler :

  • private : uniquement la classe peut utiliser.
  • protected : uniquement la classe et les classes filles peuvent utiliser.

Private

  • En Python, on ajoute __. Par exemple un champ hp devient __hp. En réalité, Python fait un renommage.
  • En C++/Java, c’est le mot clé private.

Protected

  • En Python, on ajoute _. Par exemple un champ hp devient _hp. En réalité, le champ/méthode reste utilisable partout. C’est juste une convention pour que l’on utilise pas en dehors de la classe ou classes filles.
  • En C++/Java, c’est le mot clé protected.

Public

On parle de données/méthodes publiques quand elles sont accessibles partout dans le code.

  • En Python, par défaut, les champs/méthodes sont publics (merci Python…).
  • En C++/Java, c’est public.
  • En Rust, c’est pub.

Propriétés

Parfois, c’est lourdingue de devoir appeler une méthode pour obtenir une valeur ou pour assigner une valeur. On écrit alors une propriété.

class Body:
    def __init__(self, x: float, y: float, width: float, height: float):
        self.left = x
        self.top = y
        self.width = width
        self.height = height
        
    @property    
    def right(self):
        return self.left + self.width
    
    @right.setter
    def right(self, value: float):
        self.left = value - self.width

Polymorphisme par héritage

Le polymorphisme par héritage permet d’appeler la méthode sur une classe bien que l’on ne connaisse pas le type précis.

class Animal():
    pass

class Cat(Animal):
    def speak(self):
        print("miaou")

class Dog(Animal):
    def speak(self):
        print("waouf")

L: list[Animal] = [Cat(), Dog(), Cat(), Cat()]

for animal in L:
    animal.speak()

Classe abstraite

Une classe abstraite est une classe où il y a une méthode non définie. On ne peut pas instancier un objet d’une classe abstraite.

Python ne gère pas la notion de classe abstraite directement dans le langage. Donc les concepteurs ont créé une librairie pour le faire : abc pour Abstract Base Classes. C’est à elle qu’’il y a une erreur qu’on essaie d’instantier une classe abstraite.

from abc import ABCMeta, abstractmethod

class Animal(metaclass=ABCMeta):
    def hello(self):
        print("hello")

    @abstractmethod
    def speak(self) -> None:
        raise NotImplementedError

class Cat(Animal):
    def speak(self):
        print("miaou")

class Dog(Animal):
    def speak(self):
        print("waouf")

L: list[Animal] = [Cat(), Dog(), Cat(), Cat()]

a = Animal() #ne fonctionne pas !

for animal in L:
    animal.hello()
    animal.speak()

Interface

Une interface décrit un contrat avec des déclarations de méthodes, mais pas d’implémentation.

from abc import ABCMeta, abstractmethod

class Animal(metaclass=ABCMeta):
    @abstractmethod
    def hello(self):
        raise NotImplementedError

    @abstractmethod
    def speak(self) -> None:
        raise NotImplementedError
  • Python n’a pas de mot clé pour définir des interfaces. Donc une interface est une classe abstraite avec que des méthodes virtuelles sans implémentation. Pareil en C++.
  • Java propose un mot clé interface pour en définir.
  • Rust propose des traits, ce sont des sortes d’interfaces que l’on peut accrocher à n’importe quel type.
Travail sur (https://git.aliens-lyon.fr/enslyon-l3-prog/oop_adventure_game)[https://git.aliens-lyon.fr/enslyon-l3-prog/oop_adventure_game]