• 8 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 10/10/2023

Protégez vos classes

En cette fin de cours, je vous propose un retour aux sources : à quoi sert une classe ?

Ne vous inquiétez pas, je ne vais pas me lancer dans de grands débats philosophiques. Non, je vais simplement vous rappeler l'intérêt d'une classe !

Au début de ce cours, je vous ai expliqué qu'une classe avait deux objectifs :

  • représenter un concept : c'est plus facile de manipuler un objet bus qu'un gros paquet de variables et de fonctions emmêlées ;

  • cacher une implémentation : parfois nous n'avons pas besoin de savoir comment fonctionne précisément une méthode comme la méthode drive , par exemple : on veut juste que le bus roule sur la route !

On a beaucoup parlé des moyens pour arriver au premier objectif, mais assez peu des outils qui servent le deuxième, et c'est le moment de se rattraper !

Contrôlez l’accès

Le contrôle d'accès (ou access control, en anglais) est un moyen de limiter l'accès aux constituants d'une classe, d'un module ou d'un fichier. Pour bien comprendre comment ça marche, il me faut vous expliquer d'abord ce qu'est un module, et ce qu'est un fichier source.

Commençons par le plus simple : un fichier source, c'est tout simplement un fichier. Si vous allez dans le navigateur de Xcode, vous verrez l'ensemble des fichiers d'un projet : chaque ligne correspond à un fichier source. Dans notre Playground, vous avez tout écrit dans un unique fichier.

Un module, c'est un petit paquet de fichiers qui forment un tout. Donc cela peut être une application iPhone ou un framework. Les sources du Playground forment également un module.

Les concepts de module et de fichier source sont au cœur du système de contrôle d'accès de Swift.

Gérez les niveaux de contrôle

Avec le contrôle d'accès, on va pouvoir limiter l'accès aux classes et à leur contenu. Par exemple, on va pouvoir dire qu'une fonction dans une classe est uniquement accessible dans cette classe.

Il y existe 4 niveaux de contrôle, du plus permissif au plus restrictif :

  • publicpublic ) : les éléments publics sont accessibles partout depuis n'importe quel module et n'importe quel fichier ;

  • interneinternal ) : les éléments internes sont accessibles dans tous les fichiers du module dans lequel ils se trouvent. En revanche, ils ne sont pas accessibles à l'extérieur de ce module ;

  • privé au fichierfileprivate ) : les éléments privés au fichier ne sont accessibles que dans le fichier dans lequel ils sont définis ;

  • privéprivate ) : les éléments privés ne sont accessibles que dans le contexte dans lequel ils sont définis. Par exemple, si une méthode est privée, elle ne pourra être utilisée qu'à l'intérieur de la classe dans laquelle elle se trouve.

Par défaut, tous les éléments sont au niveau interne. Donc tous les éléments sont par défaut disponibles dans le module qui les contient.

Voici un schéma qui résume les différents niveaux de contrôle d'accès :

Une illustration des niveaux de contrôle d'accès : public, interne, privé au fichier et privé.
Les niveaux de contrôle d'accès

Mettez les niveaux de contrôle en pratique

Assez de théorie, je sais que vous avez besoin de voir concrètement ce que ça donne ! Alors, allons-y. Prenons notre classe SchoolBus :

class SchoolBus: Bus {
var schoolName = ""

 

   override func drive(road: Road) {
      // (...)
   }

 

   func shouldPickChildren() -> Bool {
      // (...)
   }

 

   func pickChildren(from roadSection: RoadSection) {
      // (...)
   }

 

   func dropChildren() {
      // (...)
   }
}

Nous avons donc 4 méthodes dans cette classe. Ces méthodes sont par défaut au niveau de contrôle interne et disponibles dans tout le module, en l'occurrence le Playground.

Or, les fonctions shouldPickChildren , pickChildren et dropChildren n'ont pas besoin d'être accessibles partout dans le Playground. Elles sont uniquement utilisées à l'intérieur de la classe dans la méthode drive. Donc nous pouvons les marquer comme privées pour limiter leur utilisation à l'intérieur de la classe. Pour cela, il suffit d'écrire le nom du niveau de contrôle souhaité devant la déclaration de la méthode :

class SchoolBus: Bus {
   var schoolName = ""

 

   override func drive(road: Road) {
      // (...)
   }

 

   private func shouldPickChildren() -> Bool {
      // (...)
   }

 

   private func pickChildren(from roadSection: RoadSection) {
         // (...)
   }

 

   private func dropChildren() {
         // (...)
   }
}

Maintenant, si j'essaie d'utiliser ces fonctions en dehors de la classe, cela n'est pas possible :

var schoolBus = SchoolBus(driverName: "Joe")
schoolBus.dropChildren() // ERREUR

Nous venons de protéger notre classe SchoolBus ! Si quelqu'un l'utilise désormais, il n'aura pas accès à ces méthodes, et cela lui évitera de faire n'importe quoi avec. C'est la raison pour laquelle je vous recommande de toujours définir des niveaux de contrôle les plus stricts possible.

Au-delà de la sécurité, le contrôle d'accès est très important pour la lisibilité du code. Le contrôle d'accès permet de rendre très claire son intention. Si un développeur doit lire le contenu de ma classe SchoolBus, il saura en un clin d'œil que la classe ne contient qu'une fonction utilisable à l'extérieur et que les autres, par conséquent, sont uniquement utilisées dans la classe.

Pour vous donner une preuve, je vous invite à aller jeter un œil aux sources du Playground. Les sources du Playground sont considérées comme un module indépendant de ce dernier. Du coup, le contrôle d'accès y joue un rôle primordial :

Même si vous ne comprendrez pas le détail des implémentations, je suis certain que le contrôle d'accès vous donnera déjà une idée du fonctionnement global de ces sources.

Vous verrez dans le fichier Canvas.swift que la classe est définie comme publique. En effet, on en a besoin dans le Playground. Et seules 5 fonctions sont définies comme publiques : ce sont celles que vous connaissez.

Modifiez le contrôle d'accès des classes

Pour l'instant, nous avons seulement vu l'exemple d'une méthode privée. Mais sachez que l'on peut, de la même manière, modifier le contrôle d'accès des propriétés et des classes. Pour cela, il suffit d'écrire le mot-clé correspondant au niveau de contrôle souhaité devant la déclaration :

public class publicClass {
   internal var internalProperty = 0

 

   fileprivate let filePrivateConstant = "Coucou"

 

   private func privateFunction() {
   }
}

Pour terminer ce chapitre, je vous donne deux petites règles :

  1. Hiérarchie du contrôle. Un élément ne peut pas avoir un niveau plus permissif que celui qui le contient. Par exemple, je ne peux pas avoir une propriété au niveau public dans une classe au niveau privé :

    private class myPrivateClass {public var myPublicProperty = 0 // Impossible
    }
  2. Contrôle par défaut. Le niveau de contrôle par défaut est interne, comme je vous l'ai dit tout à l'heure. Mais tous les membres d'une classe (propriétés et méthodes) ont par défaut le niveau de contrôle de la classe dans laquelle ils sont définis. Donc si une classe a pour niveau fileprivate , tous ses membres auront par défaut le niveau de contrôle fileprivate . Par exemple :

fileprivate class myFilePrivateClass {
    var implicitFilePrivateProperty = 0 // niveau de contrôle fileprivate par défaut
     private var explicitFilePrivateProperty = 0 // niveau de contrôle private car précisé
}

À vous de jouer !

Quand vous êtes prêts, un exercice vous attend sur Replit !

Pour accéder à la solution :

  1. Soumettez votre projet avec le bouton "Submit" en haut à droite, 

  2. Cliquez sur le titre de l'exercice en haut à gauche de la fenêtre,

  3. Puis sur "OCswiftpoo",

  4. Cliquez sur "Fork the solution".

En résumé

  • Le contrôle d'accès permet de limiter l'accès à certains éléments d'un programme.

  • Il existe 4 niveaux de contrôle d'accès : public, interne, privé au fichier, privé.

  • Le contrôle d'accès permet d'améliorer la lisibilité du code en exprimant son intention concernant un élément du programme.

  • Un élément ne peut pas avoir un niveau plus permissif que celui qui le contient.

  • Tous les membres d'une classe ont par défaut le niveau de contrôle de la classe dans laquelle ils sont définis, sauf si la classe est public .

Désormais vous savez utiliser correctement les contrôles d’accès pour vos variables et vos classes. Ça en fait des notions sur la POO ! Je vous propose qu’on fasse un petit point ensemble sur tout ce qu’on vient de voir !

Exemple de certificat de réussite
Exemple de certificat de réussite