oopCommencer avec oop


Remarques

La programmation orientée objet (OOP) est un paradigme de programmation basé sur le concept "d'objets", pouvant contenir des données, sous la forme de champs, souvent appelés attributs; et code, sous la forme de procédures, souvent appelées méthodes.

introduction

OOP - La programmation orientée objet est un paradigme de programmation très utilisé de nos jours. Dans la POO, nous modélisons les problèmes du monde réel en utilisant des objets et des comportements, afin de les résoudre par programmation.

Il existe quatre principaux concepts de POO

  1. Héritage
  2. Polymorphisme
  3. Abstraction
  4. Encapsulation

Ces quatre concepts réunis servent à développer des programmes en POO.

Il existe divers langages qui suppriment la programmation orientée objet. Les langues les plus populaires sont

  • C ++
  • Java
  • C #
  • Python (Python n'est pas entièrement orienté objet, mais possède la plupart des fonctionnalités de la POO)

Introduction à la POO

Intoduction

La programmation orientée objet (principalement appelée POO) est un paradigme de programmation pour résoudre des problèmes.
La beauté d'un programme OO (orienté objet) est que nous considérons le programme comme un groupe d'objets communiquant entre eux, plutôt que comme un script séquentiel suivant des ordres spécifiques.

De nombreux langages de programmation prennent en charge la POO, les plus populaires sont:

  • Java
  • C ++
  • c #

Python est également connu pour prendre en charge la POO mais il lui manque quelques propriétés.


Terminologie POO

Le terme le plus fondamental de la POO est une classe .
Une classe est fondamentalement un objet , qui a un état et fonctionne selon son état.

Un autre terme important est une instance .
Considérez une classe comme un modèle utilisé pour créer des instances d'elle-même. La classe est un modèle et la ou les instances sont les objets concrets.

Une instance créée à partir de la classe A est généralement appelée à partir du type "A", exactement comme le type 5 est int et le type "abcd" est une chaîne .

Un exemple de création d'une instance nommée insance1 de type (classe) ClassA :

Java

ClassA instance1 = new ClassA();
 

C ++

ClassA instance1;
 

ou

ClassA *instance1 = new ClassA(); # On the heap
 

Python

instance1 = ClassA()
 

Comme vous pouvez le voir dans l'exemple ci-dessus, dans tous les cas, le nom de la classe a été mentionné et après cela, il y avait des parenthèses vides (sauf pour le C ++ où les parenthèses peuvent être supprimées si elles sont vides). Dans ces parenthèses, nous pouvons transmettre des arguments au constructeur de notre classe.

Un constructeur est une méthode d'une classe appelée chaque fois qu'une instance est créée. Il peut prendre des arguments ou non. Si le programmeur ne spécifie aucun constructeur pour une classe qu'ils construisent, un constructeur vide sera créé (un constructeur qui ne fait rien).
Dans la plupart des langues, le constructeur est défini comme une méthode sans définir son type de retour et avec le même nom de la classe (exemple dans quelques sections).

Un exemple de création d'une instance nommée b1 de type (classe) ClassB . Le constructeur de ClassB prend un argument de type int :

Java

ClassA instance1 = new ClassA(5);
 

ou

int i = 5;
ClassA instance1 = new ClassA(i);
 

C ++

ClassA instance1(5);
 

Python

instance1 = ClassA(5)
 

Comme vous pouvez le constater, le processus de création d'une instance est très similaire au processus d'appel d'une fonction.


Fonctions et méthodes

Les deux fonctions et méthodes sont très similaires, mais dans la conception orientée objet (OOD), chacune a sa propre signification.
Une méthode est une opération effectuée sur une instance d'une classe. La méthode elle-même utilise généralement l'état de l'instance pour fonctionner.
Pendant ce temps, une fonction appartient à une classe et non à une instance spécifique. Cela signifie qu'il n'utilise pas l'état de la classe ou des données stockées dans une instance.

A partir de maintenant, nous montrerons nos exemples uniquement en Java, car la POO est très claire dans ce langage, mais les mêmes principes fonctionnent dans tout autre langage de POO.

En Java, une fonction a le mot statique dans sa définition, comme ceci:

// File's name is ClassA
public static int add(int a, int b) {
    return a + b;
}
 

Cela signifie que vous pouvez l'appeler de n'importe où dans le script.

// From the same file
System.out.println(add(3, 5));

// From another file in the same package (or after imported)
System.out.println(ClassA.add(3, 5));
 

Lorsque nous appelons la fonction depuis un autre fichier, nous utilisons le nom de la classe (en Java, c'est aussi le nom du fichier), cela donne l'intuition que la fonction appartient à la classe et non à l'une de ses instances.

En revanche, nous pouvons définir une méthode dans ClassA comme ceci:

// File's name is ClassA
public int subtract(int a, int b){
    return a - b;
}
 

Après cette décomposition, nous pouvons appeler cette méthode comme suit:

ClassA a = new ClassA();
System.out.println(a.subtract(3, 5));
 

Ici, nous devions créer une instance de ClassA afin d'appeler sa méthode soustraction. Notez que nous NE pouvons PAS faire ce qui suit:

System.out.println(ClassA.subtract(3, 5));
 

Cette ligne produira une erreur de compilation en se plaignant d'avoir appelé cette méthode non-statique sans instance.


Utiliser l'état d'une classe

Supposons que nous voulions implémenter à nouveau notre méthode de soustraction , mais cette fois, nous voulons toujours soustraire le même nombre (pour chaque instance). Nous pouvons créer la classe suivante:

class ClassB {

    private int sub_amount;

    public ClassB(int sub_amount) {
        this.sub_amount = sub_amount;
    }

    public int subtract(int a) {
        return a - sub_amount;
    }

    public static void main(String[] args) {
        ClassB b = new ClassB(5);
        System.out.println(b.subtract(3)); // Ouput is -2
    }
}
 

Lorsque nous exécutons ce code, une nouvelle instance nommée b de la classe ClassB est créée et son constructeur est alimenté par la valeur 5 .
Le constructeur prend maintenant le sous- nombre donné et le stocke comme son propre champ privé, également appelé sub_amount (cette convention est très connue en Java, pour nommer les arguments de la même manière que les champs).
Après cela, nous imprimons à la console le résultat de l'appel de la méthode soustraction sur b avec la valeur 3 .

Notez que dans l'implémentation de soustraire nous n'utilisons pas this. comme dans le constructeur.
En Java, this ne doit être écrit que si une autre variable portant le même nom est définie dans cette étendue. Le même fonctionne avec le self de Python.
Donc, quand on utilise sub_amount en soustraction, on fait référence au champ privé qui est différent pour chaque classe.

Un autre exemple à souligner.
Modifions simplement la fonction principale du code ci-dessus comme suit:

ClassB b1 = new ClassB(1);
ClassB b2 = new ClassB(2);

System.out.println(b1.subtract(10)); // Output is 9
System.out.println(b2.subtract(10)); // Output is 8
 

Comme on peut le voir, b1 et b2 sont indépendants et chacun a son propre état .


Interfaces et Héritage

Une interface est un contrat, elle définit les méthodes d'une classe et donc ses capacités. Une interface n'a pas d'implémentation, elle ne définit que ce qui doit être fait.
Un exemple en Java serait:

interface Printalbe {
    public void print();
}
 

L'interface Printalbe définit une méthode appelée print mais elle ne donne pas son implémentation (assez bizarre pour Java). Chaque classe qui se déclare comme implementing cette interface doit fournir une implémentation à la méthode draw. Par exemple:

class Person implements Printalbe {

    private String name;

    public Person(String name) {
        this.name = name;
    }

    public void print() {
        System.out.println(name);
    }
}
 

Si Person se déclarait comme implémentant Drawable mais ne fournissait pas d'implémentation à imprimer , il y aurait une erreur de compilation et le programme ne compilerait pas.

L'héritage est un terme qui désigne une classe étendant une autre classe. Par exemple, disons que nous avons maintenant une personne qui a un âge. Une façon d'implémenter une telle personne serait de copier la classe Person et d'écrire une nouvelle classe appelée AgedPerson qui possède les mêmes champs et méthodes, mais une autre propriété -age.
Ce serait terrible car nous dupliquons tout notre code pour ajouter une fonctionnalité simple à notre classe.
Nous pouvons utiliser l'héritage pour hériter de Person et obtenir ainsi toutes ses fonctionnalités, puis les améliorer avec notre nouvelle fonctionnalité, comme ceci:

class AgedPerson extends Person {

    private int age;

    public AgedPerson(String name, int age) {
        super(name);
        this.age = age;
    }

    public void print() {
        System.out.println("Name: " + name + ", age:" + age);
    }
}
 

Il y a quelques nouvelles choses qui se passent:

  • Nous avons utilisé le mot sauvé extends pour indiquer que nous héritons de la personne (et aussi sa mise en œuvre imprimable, donc on n'a pas besoin de déclarer la implementing Printable en implementing Printable à nouveau).
  • Nous avons utilisé le mot de sauvegarde super pour appeler le constructeur de Person .
  • Nous avons remplacé la méthode d' impression de Person par une nouvelle.

Cela devient assez technique Java, donc je ne vais pas aller plus loin dans ce sujet. Mais je mentionnerai qu’il ya beaucoup de cas extrêmes à connaître concernant l’héritage et les interfaces avant de commencer à les utiliser. Par exemple, quelles méthodes et fonctions sont héritées? Qu'advient-il des champs privés / publics / protégés lors de l'héritage d'une classe? etc.

Classe abstraite

Une classe abstraite est un terme assez avancé dans la POO qui décrit une combinaison des interfaces et de l'héritage. Il vous permet d'écrire une classe contenant des méthodes / fonctions implémentées et non implémentées. En Java, cela se fait en utilisant le mot-clé abstract et je ne l'expliquerai pas plus rapidement qu'un exemple simple:

abstract class AbstractIntStack {

    abstract public void push(int element);

    abstract public void pop();

    abstract public int top();

    final public void replaceTop(int element) {
        pop();
        push(element);
    }
}
 

Remarque: le mot clé final indique que vous ne pouvez pas remplacer cette méthode lorsque vous héritez de cette classe. Si une classe est déclarée finale, alors aucune classe ne peut en hériter du tout.