Les Classes S4 (Formalisme et Robustesse)

Authors

Wilson Toussile1 2

1ENSPY, 2ESSFAR

Published

May 29, 2025

1 Définition de classes S4 avec setClass()

Le système de classes S4 offre une approche plus formelle et rigoureuse de la programmation orientée objet en R. Les classes S4 sont définies explicitement à l’aide de la fonction

setClass()

Example 1 (Premier exemple)  

Code
# Définition de la classe "personne"
setClass(
1  "Personne",
2  slots = c(nom = "character", age = "numeric")
)

# Définition d'un constructeur
Personne <- function(nom, age) {
  # Vérification de la validité des données
  if (!is.character(nom)) {
    stop("Le nom doit être une chaîne de caractères.")
  }
  if (!is.numeric(age) || age < 0) {
    stop("L'âge doit être un nombre positif.")
  }
  # Création de l'objet "personne"
3  new("Personne", nom = nom, age = age)
}
1
Nom de la classe
2
Spécifications des attributs (emplacements)
3
Instanciation dans le constructeur
Code
# Instancier un objet de classe Personne
Personne("Jean", 57)
An object of class "Personne"
Slot "nom":
[1] "Jean"

Slot "age":
[1] 57

2 Emplacements (slots) et types de données

Dans les classes S4, les attributs sont appelés emplacements (slots). Chaque emplacement a un nom et un type de données spécifié. Cela permet une vérification stricte des types, ce qui rend le code plus robuste.

Example 2  

Code
# Afficher les emplacements de la classe "personne"
slotNames("Personne")
[1] "nom" "age"
Code
# Afficher les types des emplacements
getClass("Personne")@slots
$nom
[1] "character"
attr(,"package")
[1] "methods"

$age
[1] "numeric"
attr(,"package")
[1] "methods"

3 Définition de méthodes S4 avec setMethod()

Les méthodes S4 sont définies à l’aide de la fonction setMethod(). Cette fonction permet de spécifier une fonction générique, la signature de la méthode (les types d’arguments) et le code de la méthode.

Example 3  

Code
# Définition de la méthode générique 'print' pour la classe "Personne"
setMethod(
1  "print",
2  "Personne",
  function(x) {
    cat("Personne :", x@nom, "\n")
    cat("Âge :", x@age, "ans\n")
3  }
)

# Création d'un objet "personne"
john <- Personne(nom = "John Doe", age = 30)

# Appel de la fonction print
print(john)
1
Nom de la méthode générique
2
Nom de la classe concernée
3
Code de la méthode
Personne : John Doe 
Âge : 30 ans

4 Accesseurs et Mutateurs

Les accesseurs et les mutateurs sont des méthodes spéciales qui permettent d’accéder aux emplacements (slots) d’un objet S4 de manière contrôlée. Ils sont particulièrement utiles pour :

  • Protéger les données internes de l’objet.
  • Effectuer des vérifications ou des transformations avant de renvoyer ou de modifier une valeur.
  • Fournir une interface plus conviviale pour l’accès en lecture ou en écriture aux emplacements.
Différence entre Accesseurs et Mutateurs
  • Accesseurs (getters) : Fonctions qui permettent d’accéder (en lecture) à un attribut d’un objet.
  • Mutateurs (setters) : Fonctions qui permettent de modifier un attribut d’un objet

Example 4 (Classe Cercle)  

Code
# Définition de la classe Cercle
setClass("Cercle",
  slots = list(
    rayon = "numeric",
    centre = "numeric" 
  )
)

# Constructeur pour la classe Cercle
Cercle <- function(rayon, centre = c(0, 0)) { # Centre par défaut à (0, 0)
  if (rayon <= 0) {
    stop("Le rayon doit être un nombre positif.")
  }
  if (length(centre) != 2 || !is.numeric(centre)) {
    stop("Le centre doit être un vecteur numérique de longueur 2.")
  }
  new("Cercle", rayon = rayon, centre = centre)
}

# Est ce Cercle?
is.Cercle <- function(obj){
  is(obj, "Cercle")
}

# Accesseur (en lecture) pour le rayon
setGeneric("rayon", function(x) standardGeneric("rayon"))
[1] "rayon"
Code
setMethod("rayon", "Cercle", function(x) x@rayon)

# Accesseur (en lecture) pour le centre
setGeneric("centre", function(x) standardGeneric("centre"))
[1] "centre"
Code
setMethod("centre", "Cercle", function(x) x@centre)

# Accesseur (en lecture) pour le diamètre
setGeneric("diametre", function(x) standardGeneric("diametre"))
[1] "diametre"
Code
setMethod("diametre", "Cercle", function(x) 2 * rayon(x))

# Mutateur pour le rayon (avec vérification de validité)
setGeneric("rayon<-", function(x, value) standardGeneric("rayon<-"))
[1] "rayon<-"
Code
setMethod("rayon<-", "Cercle", function(x, value) {
  if (value <= 0) {
    stop("Le rayon doit être un nombre positif.")
  }
  x@rayon <- value
  x
})

# Mutateur pour le centre (avec vérification de validité)
setGeneric("centre<-", function(x, value) standardGeneric("centre<-"))
[1] "centre<-"
Code
setMethod("centre<-", "Cercle", function(x, value) {
  if (length(value) != 2 || !is.numeric(value)) {
    stop("Le centre doit être un vecteur numérique de longueur 2.")
  }
  x@centre <- value
  x
})
Code
# Création d'un objet Cercle
cercle1 <- Cercle(rayon = 5, centre = c(1, 2))

# Est-ce un Cercle?
is.Cercle(cercle1)
[1] TRUE
Code
# Utilisation des accesseurs
rayon(cercle1)
[1] 5
Code
centre(cercle1)
[1] 1 2
Code
diametre(cercle1)
[1] 10
Code
# Utilisation des mutateurs
rayon(cercle1) <- 7
centre(cercle1) <- c(3, 4)

# Une erreur
# rayon(cercle1) <- -7

# Affichage des valeurs mises à jour
rayon(cercle1)
[1] 7
Code
centre(cercle1)
[1] 3 4
Code
diametre(cercle1)
[1] 14
Note

Noter la différence entre les accesseurs et les mutateurs!

5 Héritage en S4

S4 offre un mécanisme d’héritage formel et contrôlé. Une classe peut hériter des emplacements et des méthodes d’une autre classe.

Example 5  

Code
# Définition de la classe "etudiant" qui hérite de "Personne"
setClass("Etudiant",
  slots = c(matricule = "character"),
  contains = "Personne"
)

# Constructeur
Etudiant <- function(nom, age, matricule){
  # Ajouter les contrôles
  new("Etudiant", nom = nom, age = age, matricule = matricule)
}

# Création d'un objet "etudiant"
alice <- Etudiant(nom = "Alice Smith", age = 20, matricule = "12345")

# Appel de la fonction print (héritée de "Personne")
print(alice)
Personne : Alice Smith 
Âge : 20 ans

6 Exemples avancés et cas d’utilisation spécifiques

S4 est souvent utilisé pour :

  • Le développement de packages R nécessitant une grande fiabilité.
  • La modélisation de données complexes.
  • Les applications scientifiques et statistiques avancées.

7 Avantages et limites de S4

7.1 Avantages

  • Robustesse et sécurité accrues grâce à la vérification des types.
  • Meilleure organisation du code et plus grande clarté.
  • Gestion sophistiquée de l’héritage et de la distribution des méthodes.

7.2 Limites

  • Plus complexe et verbeux que S3 ou R6.
  • Peut être plus difficile à apprendre et à utiliser pour les débutants.

Dans la section suivante, nous explorerons le système de classes R6, qui offre une approche plus intuitive de la POO en R.

Bien sûr, voici une proposition de contenu au format Quarto pour la section “Les Classes R6 (POO Classique)” :