• 4 heures
  • Facile

Ce cours est visible gratuitement en ligne.

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 15/02/2023

"S" pour Single Responsibility Principle ou Principe de responsabilité unique

Principe de responsabilité unique

La première lettre de l'acronyme SOLID est "S", pour "single responsibility principle" ou principe de responsabilité unique en français. Nous l'avons déjà évoqué dans la première partie, lors de la présentation de l'architecture MVC. Comme vous le savez, l'architecture MVC permet de scinder le code en différents éléments pour en faciliter la lecture. Chaque composant (modèle, vue et contrôleur) dispose de son propre rôle ou responsabilité.

Qu'est-ce qu'une responsabilité ?

Une responsabilité est l'activité que doit accomplir l'application, à savoir ses méthodes, classes et modules.

L'objectif est de faire en sorte que chacun de ces éléments n'ait qu'une seule mission.

Attention, cela ne veut pas dire qu'une classe ne doit comporter qu'une seule méthode ou une seule propriété, mais que toutes les propriétés et méthodes d'une classe doivent servir l'objectif pour lequel la classe est conçue.

Si un élément porte une trop grande responsabilité, on dit qu'il est couplé. Par exemple, si un bloc de code doit connaître la classe B pour pouvoir utiliser la classe A, on dit que les classes A et B sont couplées. Sur le long terme, cet agencement complique les choses, car il devient difficile de modifier le code sans entraîner de conséquences sur d'autres parties de ce code. Nous discuterons du couplage plus en détail dans la prochaine chapitre.

Votre objectif sera de trouver le bon degré de couplage pour assurer la cohésion de votre application. La cohésion indique dans quelle mesure une classe respecte le principe de responsabilité unique. On dit qu'une classe présente une cohésion élevée, lorsqu'elle respecte à la lettre ce principe. À l'inverse, une classe ayant plusieurs responsabilités possède une cohésion faible et est donc à éviter.

Exemple 1 : code ne respectant pas le principe de responsabilité unique

Voici un exemple basique de classe qui ne respecte pas le principe de responsabilité unique :

public class Livre
{
 public string Auteur { get; set; }

 public string Titre { get; set; }

   public void Enregistrer()
   {
      // Enregistrement dans la base de données
   }
}

Vous vous dites probablement : "Mais où est le problème avec cet exemple ? Il me semble correct." Et pourtant, cette classe ne respecte pas le principe de responsabilité unique, car elle peut changer pour plusieurs raisons :

  1. Si vous souhaitez ajouter un attribut spécifique associé aux livres, par exemple leur nombre de pages.

  2. Si la structure de votre base de données change, vous devrez mettre à jour la façon dont le livre est enregistré, par exemple en laissant de côté le format base de données pour le format de fichier JSON.

Exemple 1 : code corrigé pour respecter le principe de responsabilité unique

Il est très facile de corriger ce code : il suffit de faire passer la méthode Enregistrer() dans une autre classe :

public class Livre
{
 public string Auteur { get; set; }

 public string Titre { get; set; }
}

public class ServiceDonnees
{
   public void Enregistrer(Livre livre)
   {
      // Enregistrement dans la base de données
   }
}

Exemple 2 : code ne respectant pas le principe de responsabilité unique

Dans cet exemple, la méthodeCreerPublication()accomplit trop de choses et ne respecte donc pas le principe de responsabilité unique.

public class Utilisateur
{
   public void CreerPublication(DbContext dbContext, string publierMessage)
   {
      try
      {
         dbContext.Add(publierMessage);
      }
      catch(Exception ex)
      {
         dbContext.LogError("Erreur :", ex.ToString());
         File.WriteAllText("Log.txt", ex.ToString());
      }
   }
}

La méthodeCreerPublication()possède beaucoup trop de responsabilités :

  1. Ajouter une nouvelle publication à la base de données.

  2. Consigner une erreur dans la base de données.

  3. Consigner une erreur dans un fichier local.

 Exemple 2 : code corrigé pour respecter le principe de responsabilité unique

Pour corriger ce code, améliorer sa cohésion et respecter le principe de responsabilité unique, répartissez les responsabilités :

public class Publier
{
   private ConsignerErreur consignerErreur = new ConsignerErreur();

   public void CreerPublication(DbContext dbContext, string publierMessage)
   {
      try
      {
         dbContext.Add(publierMessage);
      }
      catch(Exception ex)
      {
         consignerErreur.Log(ex);
      }
   }
}

public class ConsignerErreur
{
   private DbContext _dbContext;

   public ConsignerErreur(DbContext dbContext)
   {
      _dbContext = dbContext;
   }

   public void Log(Exception ex)
   {
      _dbContext.LogError("Erreur :", ex.ToString());
      File.WriteAllText("Log.txt", ex.ToString());
   }
}

Vous disposez désormais de deux classes, chacune avec sa propre responsabilité :

  1. Créer une publication.

  2. Consigner une erreur.

En résumé 

Le respect du principe de responsabilité unique offre plusieurs avantages :

  1. La classe est bien plus facile à comprendre. Lorsqu'une classe ne fait qu'une seule chose, son code est plus clair.

  2. La classe est plus facile à maintenir. Les modifications apportées à la classe sont mieux isolées, ce qui réduit le risque de générer des bugs dans d'autres parties de votre application. 

  3. La classe est davantage réutilisable. Si votre classe possède de nombreuses responsabilités et que seulement l'une d'entre elles doit être utilisée dans une autre partie de votre application, les autres méthodes superflues qu'elle contient empêcheront qu'elle soit réutilisable. A contrario, si la classe ne détient qu'une seule responsabilité, elle peut être réutilisée sans aucune modification. 

Passons maintenant à la deuxième lettre de notre acronyme, la lettre "O", qui correspond au principe Ouvert/fermé.

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