Accéder au contenu principal

OOP en Java : Classes, objets, encapsulation, héritage et abstraction

Apprenez la programmation orientée objet en Java avec des exemples pratiques. Maîtriser les classes, les objets, l'héritage, l'encapsulation et les classes abstraites à l'aide d'un système de menu de restaurant.
Actualisé 14 févr. 2025  · 15 min de lecture

Java est régulièrement l'un des trois langages les plus populaires au monde. Son adoption dans des domaines tels que le développement de logiciels d'entreprise, les applications mobiles Android et les applications web à grande échelle est inégalée. Son système de type solide, son écosystème étendu et sa capacité à "écrire une fois, exécuter n'importe où" le rendent particulièrement attrayant pour la construction de systèmes robustes et évolutifs. Dans cet article, nous verrons comment les fonctions de programmation orientée objet de Java permettent aux développeurs d'exploiter efficacement ces capacités, en leur permettant de créer des applications maintenables et évolutives grâce à une organisation et une réutilisation appropriées du code.

Note sur l'organisation et l'exécution du code Java

Avant de commencer à écrire du code, procédons à quelques réglages.

Comme pour sa syntaxe, Java a des règles strictes en matière d'organisation du code.

Tout d'abord, chaque classe publique doit se trouver dans son propre fichier, nommé exactement comme la classe mais avec une extension.java. Ainsi, si je veux écrire une classe d'ordinateur portable , le nom de fichier doit être Laptop.java-en respectant la casse. Vous pouvez avoir des classes non publiques dans le même fichier, mais il est préférable de les séparer. Je sais que nous prenons de l'avance - nous parlons de l'organisation des cours avant même de les écrire - mais il est bon d'avoir une idée approximative de l'endroit où placer les choses à l'avance.

Tous les projets Java doivent comporter un fichier Main.java avec la classeMain. C'est ici que vous testez vos classes en créant des objets à partir d'elles.

Pour exécuter du code Java, nous utiliserons IntelliJ IDEAun IDE Java très répandu. Après avoir installé IntelliJ :

  1. Créez un nouveau projet Java (Fichier > Nouveau > Projet).
  2. Cliquez avec le bouton droit de la souris sur le dossier src pour créer le fichier Main.java et collez le contenu suivant :
public class Main {
   public static void main(String[] args) {
       // Create and tests objects here
      
   }
}

Lorsque nous parlons de classes, nous écrivons du code dans d'autres fichiers que le fichierMain.java. Mais s'il s'agit de créer et de tester desobjets , nous passons à Main.java.

Pour exécuter le programme, vous pouvez cliquer sur le bouton vert de lecture situé à côté de la méthode principale :

Capture d'écran d'une fenêtre d'éditeur dans IntelliJ IDEA pour Java

La sortie sera affichée dans la fenêtre de l'outil Exécuter en bas.

Si vous êtes totalement novice en matière de Java, veuillez consulter notre cours d'introduction à Java. Cours d'introduction à Javaqui couvre les principes fondamentaux des types de données et du flux de contrôle Java avant de poursuivre.

Sinon, plongeons dans le vif du sujet.

Classes et objets Java

Qu'est-ce qu'une classe, exactement ?

Les classes sont des constructions de programmation en Java qui permettent de représenter des concepts du monde réel. Par exemple, considérez cette classe MenuItem (créez un fichier pour écrire cette classe dans votre IDE) :

public class MenuItem {
   public String name;
   public double price;
}

La classe nous donne un plan ou un modèle pour représenter les différents éléments du menu d'un restaurant. En modifiant les deux attributs de la classe, name , et price, nous pouvons créer d'innombrables objets de menu comme un hamburger ou une salade.

Ainsi, pour créer une classe en Java, vous commencez par une ligne décrivant le niveau d'accès de la classe (private,public, ou protected) suivie du nom de la classe. Immédiatement après la mise entre parenthèses, vous décrivez les attributs de votre classe.

Mais comment créer des objets appartenant à cette classe ? Java permet cela grâce à des méthodes de construction :

public class MenuItem {
   public String name;
   public double price;
  
   // Constructor
   public MenuItem(String name, double price) {
       this.name = name;
       this.price = price;
   }
}

Un constructeur est une méthode spéciale qui est appelée lorsque nous créons un nouvel objet à partir d'une classe. Il initialise les attributs de l'objet avec les valeurs que nous avons fournies. Dans l'exemple ci-dessus, le constructeur prend un nom et un prix en paramètre et les affecte aux champs de l'objet en utilisant le mot-clé "this" pour faire référence à une future instance de l'objet.

La syntaxe du constructeur est différente de celle des autres méthodes de classe car elle ne nécessite pas de spécifier un type de retour. En outre, le constructeur doit porter le même nom que la classe et doit avoir le même nombre d'attributs que celui que vous avez déclaré après la définition de la classe. Ci-dessus, le constructeur crée deux attributs parce que nous en avons déclaré deux après la définition de la classe : name et price.

Après avoir écrit votre classe et son constructeur, vous pouvez créer des instances (objets) dans votre méthode principale :

public class Main {
   public static void main(String[] args) {
       // Create objects here
       MenuItem burger = new MenuItem("Burger", 3.5);
       MenuItem salad = new MenuItem("Salad", 2.5);
       System.out.println(burger.name + ", " + burger.price);
   }
}

Sortie :

Burger, 3.5

Ci-dessus, nous créons deux objets MenuItem dans les variables burger et salad. Comme l'exige Java, le type de la variable doit être déclaré, à savoir MenuItem. Ensuite, pour créer une instance de notre classe, nous écrivons le mot-clé new suivi de l'invocation de la méthode du constructeur.

Outre le constructeur, vous pouvez créer des méthodes ordinaires qui confèrent un comportement à votre classe. Par exemple, ci-dessous, nous ajoutons une méthode pour calculer le prix total après taxes :

public class MenuItem {
   public String name;
   public double price;
  
   // Constructor
   public MenuItem(String name, double price) {
       this.name = name;
       this.price = price;
   }
  
   // Method to calculate price after tax
   public double getPriceAfterTax() {
       double taxRate = 0.08; // 8% tax rate
       return price + (price * taxRate);
   }
}

Nous pouvons maintenant calculer le prix total, taxes comprises :

public class Main {
   public static void main(String[] args) {
       MenuItem burger = new MenuItem("Burger", 3.5);
       System.out.println("Price after tax: $" + burger.getPriceAfterTax());
   }
}

Sortie :

Price after tax: $3.78

Encapsulation

L'objectif des classes est de fournir un schéma directeur pour la création d'objets. Ces objets seront ensuite utilisés par d'autres scripts ou programmes. Par exemple, nos objets MenuItem peuvent être utilisés par une interface utilisateur qui affiche leur nom, leur prix et leur image à l'écran.

C'est pourquoi nous devons concevoir nos classes de manière à ce que leurs instances ne puissent être utilisées que de la manière que nous avons prévue. Pour l'instant, notre classe MenuItem est très basique et sujette aux erreurs. Une personne peut créer des objets aux attributs ridicules, comme une tarte aux pommes à prix réduit ou un sandwich à un million de dollars :

// Inside Main.java
MenuItem applePie = new MenuItem("Apple Pie", -5.99);  // Negative price!
MenuItem sandwich = new MenuItem("Sandwich", 1000000); // Unreasonably expensive

System.out.println("Apple pie price: $" + applePie.price);
System.out.println("Sandwich price: $" + sandwich.price);

Ainsi, la première chose à faire après avoir écrit une classe est de protéger ses attributs en limitant la façon dont ils sont créés et accédés. Pour commencer, nous voulons n'autoriser que des valeurs positives pour leprix et fixer une valeur maximale pour éviter d'afficher accidentellement des articles ridiculement chers.

Java nous permet d'accomplir cette tâche en utilisant des méthodes de type "setter" :

public class MenuItem {
   private String name;
   private double price;
   private static final double MAX_PRICE = 100.0;
  
   public MenuItem(String name, double price) {
       this.name = name;
       setPrice(price);
   }
  
   public void setPrice(double price) {
       if (price < 0) {
           throw new IllegalArgumentException("Price cannot be negative");
       }
       if (price > MAX_PRICE) {
           throw new IllegalArgumentException("Price cannot exceed $" + MAX_PRICE);
       }
       this.price = price;
   }
  
}

Examinons les nouveautés du bloc de code ci-dessus :

1. Nous avons rendu les attributs privés en ajoutant le mot-clé private. Cela signifie qu'ils ne sont accessibles qu'à l'intérieur de la classe MenuItem. L'encapsulation commence par cette étape cruciale.

2. Nous avons ajouté une nouvelle constante: MAX_PRICE:

  • privé (accessible uniquement au sein de la classe)
  • statique (partagé par toutes les instances)
  • final (ne peut être modifié après l'initialisation)
  • fixé à 100,0 $ comme prix maximum raisonnable

3. Nous avons ajouté une méthode setPrice() qui :

  • Prend un paramètre de prix
  • Valide que le prix n'est pas négatif
  • Valide que le prix ne dépasse pas MAX_PRICE
  • Lance une exception IllegalArgumentException avec des messages descriptifs en cas d'échec de la validation.
  • Le prix n'est fixé que si toutes les validations sont réussies

4. Nous avons modifié le constructeur pour utiliser setPrice() au lieu d'assigner directement le prix. Cela permet de s'assurer que la validation des prix a lieu lors de la création de l'objet.

Nous venons de mettre en œuvre l'un des principaux piliers d'une bonne conception orientée objet - l'encapsulation. Ce paradigme permet de masquer les données et de contrôler l'accès aux attributs des objets, en garantissant que les détails de l'implémentation interne sont protégés des interférences externes et ne peuvent être modifiés qu'au moyen d'interfaces bien définies.

Faisons valoir notre point de vue en appliquant l'encapsulation à l'attributname. Imaginez un café qui ne sert que des lattes, des cappuccinos, des espressos, des americanos et des mokas.

Ainsi, les noms de nos éléments de menu ne peuvent être que l'un des éléments de cette liste. Voici comment nous pouvons appliquer cette règle dans le code :

// Rest of the class here
...
private static final String[] VALID_NAMES = {"latte", "cappuccino", "espresso", "americano", "mocha"};
private String name;
public void setName(String name) {
   String lowercaseName = name.toLowerCase();
   for (String validName : VALID_NAMES) {
       if (validName.equals(lowercaseName)) {
           this.name = name;
           return;
       }
   }
   throw new IllegalArgumentException("Invalid drink name. Must be one of: " + String.join(", ", VALID_NAMES));
}

Le code ci-dessus met en œuvre la validation des noms pour les éléments du menu d'un café. Voyons cela en détail :

1. Tout d'abord, il définit un tableau final statique privé VALID_NAMES qui contient les seuls noms de boissons autorisés : latte, cappuccino, espresso, americano et mocha. Ce tableau étant :

  • privé : accessible uniquement au sein de la classe
  • statique : partagé par toutes les instances
  • final : ne peut être modifié après l'initialisation

2. Il déclare un champ privé String name pour stocker le nom de la boisson.

3. La méthode setName() met en œuvre la logique de validation :

  • Prend en paramètre un nom de type chaîne
  • Le convertit en minuscules pour rendre la comparaison insensible à la casse.
  • Boucle sur le tableau VALID_NAMES
  • Si une correspondance est trouvée, le nom est défini et le message est renvoyé.
  • Si aucune correspondance n'est trouvée, une exception de type IllegalArgumentException est levée avec un message descriptif énumérant toutes les options valides.

Voici la classe complète jusqu'à présent :

public class MenuItem {
   private String name;
   private double price;

   private static final String[] VALID_NAMES = {"latte", "cappuccino", "espresso", "americano", "mocha"};

   private static final double MAX_PRICE = 100.0;

   public MenuItem(String name, double price) {
       setName(name);
       setPrice(price);
   }

   public void setName(String name) {
       String lowercaseName = name.toLowerCase();
       for (String validName : VALID_NAMES) {
           if (validName.equals(lowercaseName)) {
               this.name = name;
               return;
           }
       }
       throw new IllegalArgumentException("Invalid drink name. Must be one of: " + String.join(", ", VALID_NAMES));
   }

   public void setPrice(double price) {
       if (price < 0) {
           throw new IllegalArgumentException("Price cannot be negative");
       }
       if (price > MAX_PRICE) {
           throw new IllegalArgumentException("Price cannot exceed $" + MAX_PRICE);
       }
       this.price = price;
   }
}

Après avoir protégé la façon dont les attributs sont créés, nous voulons également protéger la façon dont on y accède. Pour ce faire, vous pouvez utiliser des méthodes de type "getter" :

public class MenuItem {
   // Rest of the code here
   ...
   public String getName() {
       return name;
   }
   public double getPrice() {
       return price;
   }
}

Les méthodes Getter fournissent un accès contrôlé aux attributs privés d'une classe. Ils résolvent le problème de l'accès direct aux attributs, qui peut entraîner des modifications non souhaitées et rompre l'encapsulation.

Par exemple, sans getters, nous pourrions accéder directement aux attributs :

MenuItem item = new MenuItem("Latte", 4.99);
String name = item.name; // Direct access to attribute
item.name = "INVALID"; // Can modify directly, bypassing validation

Avec les getters, nous assurons un accès approprié :

MenuItem item = new MenuItem("Latte", 4.99);
String name = item.getName(); // Controlled access through getter
// item.name = "INVALID"; // Not allowed - must use setName() which validates

Cette encapsulation :

  1. Protège l'intégrité des données en empêchant les modifications non valides
  2. Permet de modifier l'implémentation interne sans affecter le code qui utilise la classe
  3. Fournit un point d'accès unique qui peut inclure une logique supplémentaire si nécessaire
  4. rend le code plus facile à maintenir et moins sujet aux bogues

Héritage

Notre classe commence à avoir fière allure, mais elle présente de nombreux problèmes. Par exemple, pour un grand restaurant servant de nombreux types de plats et de boissons, la classe n'est pas assez flexible.

Si nous voulons ajouter différents types de produits alimentaires, nous nous heurterons à plusieurs difficultés. Certains plats peuvent être préparés pour être emportés, tandis que d'autres doivent être consommés immédiatement. Les prix et les remises peuvent varier d'un produit à l'autre. Les plats peuvent nécessiter un suivi de la température ou un stockage spécial. Les boissons peuvent être chaudes ou froides avec des ingrédients personnalisables. Les articles peuvent nécessiter des informations sur les allergènes et des options de portions. Le système actuel ne permet pas de répondre à ces différentes exigences.

L'héritage offre une solution élégante à tous ces problèmes. Il nous permet de créer des versions spécialisées d'éléments de menu en définissant une classe de base MenuItem avec des attributs communs, puis en créant des classes enfantines qui héritent de ces éléments de base tout en ajoutant des caractéristiques uniques. 

Par exemple, nous pourrions avoir une classe Drink pour les boissons avec des options de température, une classe Food pour les articles nécessitant une consommation immédiate et une classe Dessert pour les articles ayant des besoins de stockage particuliers - toutes ces classes héritant de la fonctionnalité principale des articles de menu.

Extension des classes

Mettons en œuvre ces idées en commençant par Drink:

public class Drink extends MenuItem {
   private boolean isCold;
  
   public Drink(String name, double price, boolean isCold) {
       this.name = name;
       this.price = price;
       this.isCold = isCold;
   }
  
   public boolean getIsCold() {
       return isCold;
   }
  
   public void setIsCold(boolean isCold) {
       this.isCold = isCold;
   }
}

Pour définir une classe enfant qui hérite d'une classe parent, nous utilisons le mot-cléextends après le nom de la classe enfant, suivi de celui de la classe parent. Après la définition de la classe, nous définissons les nouveaux attributs de cet enfant et implémentons son constructeur.

Mais remarquez que nous devons répéter l'initialisation de name et price avec isCold. Ce n'est pas idéal car la classe mère peut avoir des centaines d'attributs. En outre, le code ci-dessus provoquera une erreur lorsque vous le compilerez, car ce n'est pas la bonne façon d'initialiser les attributs de la classe parente. La bonne méthode consiste à utiliser le mot-clé super:

public class Drink extends MenuItem {
   private boolean isCold;
  
   public Drink(String name, double price, boolean isCold) {
       super(name, price);
       this.isCold = isCold;
   }
  
   public boolean getIsCold() {
       return isCold;
   }
  
   public void setIsCold(boolean isCold) {
       this.isCold = isCold;
   }
}

Le mot-clésuper est utilisé pour appeler le constructeur de la classe mère. Dans ce cas, super(name, price) appelle le constructeur deMenuItem pour initialiser ces attributs, évitant ainsi la duplication du code. Il suffit d'initialiser le nouvel attribut isCold spécifique à la classeDrink.

Ce mot-clé est très flexible car vous pouvez l'utiliser pour faire référence à la classe mère dans n'importe quelle partie de la classe enfant. Par exemple, pour appeler une méthode parent, vous utilisez super.methodName(), tandis que super.attributeName est destiné aux attributs.

Remise en cause de la méthode

Supposons maintenant que nous voulions ajouter une nouvelle méthode à nos classes pour calculer le prix total après taxes. Étant donné que les taux d'imposition peuvent varier d'un article de menu à l'autre (par exemple, aliments préparés ou boissons emballées), nous pouvons utiliser la méthode de superposition pour mettre en œuvre des calculs d'impôts spécifiques dans chaque classe enfant tout en conservant un nom de méthode commun dans la classe mère.

Voici à quoi cela ressemble :

public class MenuItem {
   // Rest of the MenuItem class
  
   public double calculateTotalPrice() {
       // Default tax rate of 10%
       return price * 1.10;
   }
}
public class Food extends MenuItem {
   private boolean isVegetarian;
  
   public Food(String name, double price, boolean isVegetarian) {
       super(name, price);
       this.isVegetarian = isVegetarian;
   }
  
   @Override
   public double calculateTotalPrice() {
       // Food has 15% tax
       return super.getPrice() * 1.15;
   }
}
public class Drink extends MenuItem {
   private boolean isCold;
  
   public Drink(String name, double price, boolean isCold) {
       super(name, price);
       this.isCold = isCold;
   }
  
   @Override
   public double calculateTotalPrice() {
       // Drinks have 8% tax
       return super.getPrice() * 1.08;
   }
}

Dans cet exemple, la superposition de méthodes permet à chaque sous-classe de fournir sa propre implémentation de la méthode calculateTotalPrice():

La classe de base MenuItem définit un calcul de taxe par défaut de 10 %.

Quand Food et Drink étendent MenuItemils surchargent cette méthode pour mettre en œuvre leurs propres taux d'imposition :

  • Les produits alimentaires sont soumis à un taux d'imposition plus élevé de 15 %.
  • Les boissons bénéficient d'un taux d'imposition inférieur de 8 %.

L'annotation@Override est utilisée pour indiquer explicitement que ces méthodes remplacent la méthode de la classe mère. Cela permet de détecter les erreurs si la signature de la méthode ne correspond pas à celle de la classe mère.

Chaque sous-classe peut toujours accéder au prix de la classe parente en utilisant super.getPrice()démontrant ainsi que les méthodes surchargées peuvent utiliser les fonctionnalités de la classe parente tout en ajoutant leur propre comportement.

En bref, la superposition de méthodes fait partie intégrante de l'héritage et permet aux sous-classes de fournir leur propre implémentation des méthodes définies dans la classe mère, ce qui permet d'obtenir un comportement plus spécifique tout en conservant la même signature de méthode.

Classes abstraites

Notre hiérarchie de classes MenuItem fonctionne, mais il y a un problème : n'importe qui devrait pouvoir créer un simple objetMenuItem? Après tout, dans notre restaurant, chaque élément du menu est soit un plat, soit une boisson - il n'existe pas d'élément de menu générique.

Nous pouvons éviter cela en faisant de MenuItem une classe abstraite. Une classe abstraite ne fournit qu'un modèle de base - elle ne peut être utilisée que comme classe parente pour l'héritage, et ne peut pas être instanciée directement.

Pour rendre MenuItem abstrait, nous ajoutons le mot-clé abstract après son modificateur d'accès :

public abstract class MenuItem {
   private String name;
   private double price;
  
   public MenuItem(String name, double price) {
       setName(name);
       setPrice(price);
   }
  
   // Existing getters/setters remain the same
  
   // Make this method abstract - every subclass MUST implement it
   public abstract double calculateTotalPrice();
}

Les classes abstraites peuvent également avoir des méthodes abstraites comme calculateTotalPrice() ci-dessus. Ces méthodes abstraites servent de contrats qui obligent les sous-classes à fournir leurs implémentations. En d'autres termes, toute méthode abstraite d'une classe abstraite doit être implémentée par les classes enfantines.

Réécrivons donc Food et Drink en tenant compte de ces changements :

public class Food extends MenuItem {
   private boolean isVegetarian;
  
   public Food(String name, double price, boolean isVegetarian) {
       super(name, price);
       this.isVegetarian = isVegetarian;
   }
  
   @Override
   public double calculateTotalPrice() {
       return getPrice() * 1.15;  // 15% tax
   }
}
public class Drink extends MenuItem {
   private boolean hasCaffeine;
  
   public Drink(String name, double price, boolean hasCaffeine) {
       super(name, price);
       this.hasCaffeine = hasCaffeine;
   }
  
   @Override
   public double calculateTotalPrice() {
       return getPrice() * 1.10;  // 10% tax
   }
}

Grâce à la mise en œuvre de ce système de menus, nous avons vu comment l'abstraction et l'héritage fonctionnent ensemble pour créer un code flexible et facile à maintenir qui peut facilement s'adapter aux différentes exigences de l'entreprise.

Conclusion

Aujourd'hui, nous avons eu un aperçu de ce dont Java est capable en tant que langage de programmation orienté objet. Nous avons couvert les bases des classes, des objets et quelques piliers de la POO : encapsulation, héritage et abstraction à travers un système de menu de restaurant.

Pour que ce système soit prêt pour la production, il vous reste encore beaucoup de choses à apprendre, comme les interfaces (qui font partie de l'abstraction), le polymorphisme et les modèles de conception OOP. Pour en savoir plus sur ces concepts, reportez-vous à notre Introduction à la POO en Java.

Si vous souhaitez tester vos connaissances en Java, essayez de répondre à certaines des questions de notre article sur les questions d'entretien en Java. notre article Questions d'entretien sur Java.

FAQ sur la POO en Java

Quels sont les pré-requis pour suivre ce tutoriel Java OOP ?

Vous devez avoir des connaissances de base en programmation Java, notamment en ce qui concerne les types de données, les variables, le flux de contrôle (if/else, boucles) et la syntaxe de base. Notre cours Introduction à Java couvre ces fondamentaux si vous avez besoin d'une remise à niveau.

Pourquoi utiliser un système de menu de restaurant pour expliquer les concepts de la POO ?

Le système de menu d'un restaurant est un exemple intuitif qui démontre les applications réelles des principes de la POO. Il montre naturellement l'héritage (différents types d'articles de menu), l'encapsulation (protection des valeurs de prix et de nom) et les interfaces (programmes de fidélisation, contrôle de la température). La plupart des gens comprennent le fonctionnement des restaurants, ce qui facilite la compréhension des concepts.

Quelle est la différence entre les classes abstraites et les interfaces en Java ?

  • Une classe ne peut étendre qu'une seule classe abstraite mais mettre en œuvre plusieurs interfaces.
  • Les classes abstraites peuvent avoir des champs et des constructeurs, ce qui n'est pas le cas des interfaces.
  • Les classes abstraites peuvent avoir des méthodes abstraites et concrètes ; les interfaces n'ont traditionnellement que des méthodes abstraites (avant Java 8).
  • Les classes abstraites fournissent une implémentation de base, tandis que les interfaces définissent un contrat.

Bex Tuychiev's photo
Author
Bex Tuychiev
LinkedIn

Je suis un créateur de contenu en science des données avec plus de 2 ans d'expérience et l'un des plus grands followings sur Medium. J'aime écrire des articles détaillés sur l'IA et la ML dans un style un peu sarcastıc, car il faut bien faire quelque chose pour les rendre un peu moins ennuyeux. J'ai produit plus de 130 articles et un cours DataCamp, et un autre est en cours d'élaboration. Mon contenu a été vu par plus de 5 millions de personnes, dont 20 000 sont devenues des adeptes sur Medium et LinkedIn. 

Sujets

Principaux cours sur Java

cours

Introduction to Java

4 hr
6.8K
Learn Java from the ground up with this beginner-friendly course, mastering essential programming concepts and skills.
Afficher les détailsRight Arrow
Commencer le cours
Voir plusRight Arrow
Apparenté

blog

2022-2023 Rapport annuel DataCamp Classrooms

À l'aube de la nouvelle année scolaire, DataCamp Classrooms est plus motivé que jamais pour démocratiser l'apprentissage des données, avec plus de 7 650 nouveaux Classrooms ajoutés au cours des 12 derniers mois.
Nathaniel Taylor-Leach's photo

Nathaniel Taylor-Leach

8 min

blog

Q2 2023 DataCamp Donates Digest

DataCamp Donates a offert plus de 20k bourses d'études à nos partenaires à but non lucratif au deuxième trimestre 2023. Découvrez comment des apprenants défavorisés et assidus ont transformé ces opportunités en réussites professionnelles qui ont changé leur vie.
Nathaniel Taylor-Leach's photo

Nathaniel Taylor-Leach

blog

Célébration de Saghar Hazinyar : Une boursière de DataCamp Donates et une diplômée de Code to Inspire

Découvrez le parcours inspirant de Saghar Hazinyar, diplômée de Code to Inspire, qui a surmonté les défis en Afghanistan et s'est épanouie grâce à une bourse de DataCamp Donates.
Fereshteh Forough's photo

Fereshteh Forough

4 min

blog

Nous avons fait don de bourses DataCamp Premium à un million de personnes, et ce n'est pas fini.

Réparties entre nos deux programmes d'impact social, DataCamp Classrooms et #DCDonates, les bourses offrent un accès illimité à tout ce que DataCamp Premium a à offrir.
Nathaniel Taylor-Leach's photo

Nathaniel Taylor-Leach

blog

Les 20 meilleures questions d'entretien pour les flocons de neige, à tous les niveaux

Vous êtes actuellement à la recherche d'un emploi qui utilise Snowflake ? Préparez-vous à répondre à ces 20 questions d'entretien sur le flocon de neige pour décrocher le poste !
Nisha Arya Ahmed's photo

Nisha Arya Ahmed

20 min

Voir plusVoir plus