1. Objets et classes

Aujourd'hui, vous allez en apprendre un peu plus sur le fonctionnement d'un programme Java typique. Voici la grande nouveauté : chaque programme Java est composé de classes et d'objets.

Vous savez déjà ce que sont les classes, mais que sont les objets ?

Je vais commencer par une analogie. Imaginez que vous vouliez fabriquer un petit bateau. Vous devez d'abord créer un plan, puis le donner à l'usine, où un navire sera construit selon le plan. Ou peut-être une douzaine. Ou autant de navires que vous le souhaitez. Des dizaines de navires identiques sont construits selon un plan unique. C'est la chose importante ici.

C'est la même chose en programmation Java.

Plans

Un programmeur est comme un designer. Un concepteur crée des plans et un programmeur Java écrit des classes. Les pièces sont créées en fonction des plans et les objets sont créés en fonction des classes.

Tout d'abord, nous écrivons des classes (créons des plans), puis, au fur et à mesure que le programme s'exécute, la machine Java crée des objets basés sur ces classes. De la même manière que les navires sont créés à partir de plans.

Il n'y a qu'un seul plan, mais il peut y avoir plusieurs navires. Les navires sont distincts - ils ont des noms différents et transportent des cargaisons différentes. Mais ils sont très similaires : ils partagent tous le même design et peuvent effectuer des tâches similaires.

Ou voici une autre analogie...

Fourmilière

Une fourmilière est un bon exemple de la façon dont les objets interagissent. Il y a trois classes de fourmis dans une simple fourmilière : la reine, les soldats et les ouvrières.

Le nombre de fourmis de chaque classe est différent. Il y a une seule reine pour toute la fourmilière, mais il y a des dizaines de soldats et des centaines de fourmis ouvrières. Trois classes et des centaines d'objets. Les fourmis interagissent entre elles - avec des fourmis de leur même classe et avec des fourmis d'autres classes - selon des règles rigides.

C'est l'exemple parfait. Tout est exactement comme ça dans un programme typique. Il existe un objet principal qui crée des objets de toutes les autres classes. Les objets commencent à interagir les uns avec les autres et avec le "monde extérieur" du programme. Le comportement des objets est codé en dur en interne.

Ces deux analogies sont les deux faces d'une même médaille. La vérité est au milieu. Le premier exemple (à propos d'un plan et de navires) montre la relation entre une classe et les objets de cette classe. C'est une forte analogie. Le deuxième exemple (à propos d'une fourmilière) montre la relation entre les classes écrites et les objets qui existent au fur et à mesure que le programme s'exécute.

Vous devez d'abord écrire des classes pour chaque objet qui existera dans le programme, puis décrire également comment elles interagissent. Oui, c'est vrai, mais c'est plus facile qu'il n'y paraît.

En Java, toutes les entités sont des objets au moment de l'exécution, et écrire un programme consiste à décrire les différentes façons dont les objets interagissent. Les objets appellent simplement les méthodes les uns des autres et leur transmettent les données requises.

Documentation

Et comment savez-vous quelles données transmettre aux méthodes ? Les personnes qui vous ont précédé ont pensé à tout.

Chaque classe a généralement une description qui indique pourquoi elle a été créée. De plus, chaque méthode publique a généralement une description qui indique ce qu'elle fait et quelles données doivent lui être transmises.

Pour utiliser une classe, vous devez avoir une idée générale de ce qu'elle fait. Et vous devez savoir exactement ce que fait chaque méthode. Mais vous n'avez pas du tout besoin de savoir comment il le fait. C'est comme une baguette magique.

Examinons le code pour copier un fichier :

Copie du fichier c:\\data.txt dans le fichier c:\\result.txt
package com.codegym.lesson2;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileCopy
{
   public static void main(String[] args) throws IOException
   {
      FileInputStream fileInputStream = new FileInputStream("c:\\data.txt");
      FileOutputStream fileOutputStream = new FileOutputStream("c:\\result.txt");

      while (fileInputStream.available() > 0)
      {
         int data = fileInputStream.read();
         fileOutputStream.write(data);
      }

      fileInputStream.close();
      fileOutputStream.close();
   }
}

Si vous lisez ce code ligne par ligne, vous pouvez deviner ce qu'il fait en termes généraux. Bien que cela demande de l'expérience et de la pratique. Au bout d'un moment, ce code vous semblera familier et compréhensible.


2. Concevoir un programme

La conception de programmes est tout un art. C'est à la fois simple et difficile. Simple, car il n'y a pas de lois strictes : tout ce qui n'est pas interdit est permis. Eh bien, et c'est aussi ce qui rend les choses difficiles : il y a beaucoup de façons de faire quelque chose et ce n'est pas facile de trouver la meilleure.

Concevoir un programme, c'est comme écrire un livre. D'une part, vous écrivez simplement des lettres, des mots et des phrases. D'autre part, l'intrigue, les personnages, les contradictions internes, les conflits, le style de narration, l'intrigue, etc. sont importants.

L'essentiel est de comprendre pour qui vous écrivez le code. Et vous écrivez du code pour d'autres programmeurs .

Le développement de produits implique inévitablement des changements : quelque chose est ajouté ici, quelque chose d'autre est supprimé là, quelque chose est repensé. C'est ainsi que des projets grands, énormes et gigantesques naissent de petites itérations.

Ce qui compte le plus pour le code, c'est qu'il doit être compréhensible pour les autres programmeurs. Un code incorrect compréhensible peut être corrigé. Un code correct mais incompréhensible ne peut pas être amélioré.  Tout ce que vous pouvez faire est de le jeter.

Alors, comment écrivez-vous un bon code propre ?

Pour cela, il faut trois choses :

  • Écrire un code bon et compréhensible à l'intérieur des méthodes - c'est l'exigence la plus simple
  • Décider quelles entités doivent être incluses dans le programme
  • Diviser correctement le programme en parties logiques

Qu'y a-t-il derrière ces concepts ?

Écrire du bon code dans les méthodes

Si vous avez même des compétences de base en anglais, vous avez peut-être remarqué à quel point il est parfois facile de lire du code sous forme de phrases en anglais :

  • class Cat extends Pet— Cela signifie que la classe Cat étend la classe Pet
  • while(stream.ready())— tant que le flux est prêt...
  • if (a<b) return a; else return b— si aest inférieur à b, alors return a, sinon return b.

C'est délibéré. Java est l'un des nombreux langages qui permettent d'écrire facilement du code auto-documenté, c'est-à-dire du code compréhensible sans commentaire. Dans un bon code Java, de nombreuses méthodes se lisent comme des phrases en anglais.

Lorsque vous écrivez du code, votre tâche est de le rendre aussi simple et concis que possible. Demandez-vous simplement si votre code est facile à lire et vous commencerez à avancer dans la bonne direction.

En Java, il est d'usage d'écrire du code facile à lire. De préférence, tout le code d'une méthode tiendra sur un seul écran (c'est-à-dire 20 à 30 lignes). C'est la norme pour toute la communauté Java. Si le code peut être amélioré, il doit l'être.

La meilleure façon d'apprendre à écrire du bon code est par la pratique. Écrivez beaucoup de code, étudiez le code des autres et demandez à des collègues plus expérimentés de réviser votre code.

Et rappelez-vous qu'au moment où vous vous dites "laissez-vous tranquille", votre croissance s'arrête.

Décider quelles entités doivent être incluses dans le programme

Vous devez écrire du code que les autres programmeurs peuvent comprendre. Si 9 programmeurs sur 10 incluaient les classes A, B et C dans la conception d'un programme, alors vous devriez également créer les classes A, B et C dans votre programme. Vous devez écrire du code que les autres peuvent comprendre.

Génial, fonctionnel, rapide, mais un code non standard est un mauvais code.

Vous devez étudier les projets des autres : c'est le moyen le meilleur, le plus rapide et le plus simple de s'imprégner de toute la sagesse accumulée dans l'industrie informatique depuis des décennies.

Et en passant, vous avez déjà accès à un excellent projet populaire et bien documenté - le SDK Java . Commencez par ça.

Analysez les classes et leur organisation. Réfléchissez aux raisons pour lesquelles certaines méthodes sont statiques et d'autres non. Pourquoi les méthodes ont-elles les paramètres spécifiques qu'elles ont mais pas les autres. Pourquoi ces méthodes exactement, et pourquoi les classes sont-elles nommées comme elles sont nommées, et pourquoi sont-elles contenues dans leurs packages spécifiques.

Une fois que vous commencerez à comprendre les réponses à toutes ces questions, vous serez en mesure d'écrire du code que les autres pourront comprendre.

Cela dit, je tiens à vous mettre en garde contre l'analyse du code dans les méthodes du SDK Java. De nombreuses méthodes ont été réécrites pour maximiser la vitesse, et leur lisibilité est discutable.

Diviser correctement le programme en parties logiques

Presque chaque programme est divisé en parties ou modules. Chaque partie est responsable de son propre aspect du programme.

Un ordinateur a une carte mère, un moniteur et un clavier - ce sont tous des éléments séparés et faiblement couplés. De plus, ils interagissent de manière standardisée : USB, HDMI, etc. Si vous renversez du café sur votre clavier, vous pouvez simplement le laver dans l'évier, le laisser sécher, puis continuer à l'utiliser.

Mais un ordinateur portable est un exemple d'architecture monolithique : il semble que l'on puisse discerner des parties logiques séparées, mais elles sont beaucoup plus intégrées. Sur un MacBookPro, il faut démonter la moitié du portable pour nettoyer le clavier. Et renverser votre café sur un ordinateur portable est une raison pour commander un nouvel ordinateur portable. Pas une nouvelle tasse de café.


3. Créer vos propres classes

Mais puisque vous venez d'apprendre à programmer, vous devriez commencer petit en apprenant à créer vos propres classes.

Bien sûr, vous avez déjà créé des classes, mais vous devez apprendre à comprendre quelles classes doivent être incluses dans un programme, comment elles doivent être nommées et quelles méthodes elles doivent avoir. Et comment ils doivent interagir les uns avec les autres.

Liste des entités

Si vous ne savez pas par où commencer, recommencez depuis le début.

Lorsque vous commencez à concevoir un programme, vous pouvez simplement saisir une feuille de papier et écrire une liste des entités (objets) qui devraient figurer dans le programme. Et puis écrivez du code selon le principe que chaque entité est une classe distincte.

Exemple

Disons que vous voulez écrire un jeu d'échecs. Vous aurez besoin des entités suivantes : un échiquier et 6 types de pièces d'échecs. Les pièces se déplacent de différentes manières et ont des valeurs différentes. Il est logique qu'il s'agisse de classes distinctes. En effet, au début, plus il y a de cours, mieux c'est.

Il est très rare de rencontrer un programmeur débutant qui écrit dix classes au lieu de deux. Au lieu d'écrire dix classes, les débutants aiment écrire deux classes ou peut-être une seule. Alors, s'il vous plaît, écrivez plus de cours, mes collègues programmeurs. Et votre code deviendra plus clair pour tout le monde sauf peut-être pour vous 😛

Échecs

Supposons que nous décidions d'écrire des cours d'échecs : à quoi ressembleraient ces cours ?

L'échiquier n'est-il qu'un tableau 8 par 8 ? Il est préférable de créer une classe distincte qui stocke en interne une référence à un tableau. Ensuite, vous pouvez ajouter de nombreuses méthodes utiles à la classe "échiquier", par exemple, pour vérifier si une cellule spécifique est vide ou occupée

En général, lorsque vous démarrez, soyez toujours guidé par ce principe : un programme a plusieurs entités, et une entité a un type. Ce type est la classe.


4. Variables et méthodes statiques

N'oubliez pas non plus d'utiliser des variables et des méthodes statiques. Si vous avez une pièce d'échecs en interaction avec une autre sur l'échiquier, votre code a besoin d'une méthode qui prend des références aux première et deuxième pièces ainsi qu'à l'échiquier.

Les variables statiques, accessibles depuis n'importe où dans le programme, sont généralement utilisées pour éviter de passer constamment des références à des objets qui "existent toujours".

Par exemple, comme ceci :

Code Note
public class ChessBoard
{
   public static ChessBoard board = new ChessBoard();
   public ChessItem[][] cells = new ChessItem[8][8];
   ...
}

public class Game
{
   public static void main(String[] args)
   {
      var board = ChessBoard.board;
      board.cells[0][3] = new King(Color.WHITE);
      board.cells[0][4] = new Queen(Color.WHITE);
      ...
   }
}


Une référence à un seul ChessBoardobjet.
Un tableau bidimensionnel 8x8, pas une variable statique.








Ajoutez les pièces au plateau.

Ou au lieu d'une variable statique, vous pouvez créer une méthode qui renvoie un objet singleton. Par exemple, comme ceci :

public class ChessBoard
{
   private static ChessBoard board = new ChessBoard();
   public static ChessBoard getBoard()
   {
      return board;
   }

   public ChessItem[][] cells = new ChessItem[8][8];
   ...
}

public class Game
{
   public static void main(String[] args)
   {
      var board = ChessBoard.getBoard();
      board.cells[0][3] = new King(Color.WHITE);
      board.cells[0][4] = new Queen(Color.WHITE);
      ...
   }
}