Encapsulation (programmation informatique) - Encapsulation (computer programming)

Dans la programmation orientée objet (OOP), l' encapsulation fait référence au regroupement de données avec les méthodes qui opèrent sur ces données, ou à la restriction de l'accès direct à certains des composants d'un objet. L'encapsulation est utilisée pour masquer les valeurs ou l'état d'un objet de données structuré à l'intérieur d'une classe , empêchant l'accès direct aux clients d'une manière qui pourrait exposer des détails d'implémentation cachés ou violer l'invariance d'état maintenue par les méthodes.

Des méthodes accessibles au public sont généralement fournies dans la classe pour accéder ou modifier l'état de manière plus abstraite. Dans la pratique, des méthodes (appelées "getters" et "setters" ) sont parfois fournies pour accéder indirectement aux valeurs, mais, bien qu'elles ne constituent pas nécessairement une violation de l'encapsulation abstraite, elles sont souvent considérées comme le signe d'une programmation orientée objet potentiellement médiocre . (OOP) pratique de conception (un Anti-pattern ).

Ce mécanisme n'est pas propre à la POO. Les implémentations de types de données abstraits , par exemple les modules , offrent une forme similaire d'encapsulation. La similitude a été expliquée par les théoriciens du langage de programmation en termes de types existentiels .

Sens

Dans les langages de programmation orientés objet et dans d'autres domaines connexes, l'encapsulation fait référence à l'une des deux notions connexes mais distinctes, et parfois à leur combinaison :

  • Un mécanisme de langage pour restreindre l'accès direct à certains des composants de l' objet .
  • Une construction de langage qui facilite le regroupement de données avec les méthodes (ou d'autres fonctions) opérant sur ces données.

Certains chercheurs et universitaires en langage de programmation utilisent le premier sens seul ou en combinaison avec le second comme caractéristique distinctive de la programmation orientée objet , tandis que certains langages de programmation qui fournissent des fermetures lexicales considèrent l'encapsulation comme une caractéristique du langage orthogonale à l'orientation objet.

La deuxième définition est motivée par le fait que dans de nombreux langages orientés objet, et d'autres domaines connexes, les composants ne sont pas automatiquement masqués et cela peut être outrepassé ; ainsi, la dissimulation d'informations est définie comme une notion distincte par ceux qui préfèrent la seconde définition.

Les fonctionnalités d'encapsulation sont prises en charge à l'aide de classes dans la plupart des langages orientés objet, bien que d'autres alternatives existent également.

Encapsulation et héritage

Les auteurs de Design Patterns discutent longuement de la tension entre l' héritage et l'encapsulation et déclarent que d'après leur expérience, les concepteurs abusent de l'héritage. Ils prétendent que l'héritage casse souvent l'encapsulation, étant donné que l'héritage expose une sous-classe aux détails de l'implémentation de son parent. Comme décrit par le problème yo-yo , la surexploitation de l'héritage et donc de l'encapsulation, peut devenir trop compliquée et difficile à déboguer.

Cacher des informations

Selon la définition selon laquelle l'encapsulation « peut être utilisée pour masquer les membres de données et les fonctions membres », la représentation interne d'un objet est généralement masquée à la vue en dehors de la définition de l'objet. En règle générale, seules les propres méthodes de l'objet peuvent directement inspecter ou manipuler ses champs. Le masquage des composants internes de l'objet protège son intégrité en empêchant les utilisateurs de définir les données internes du composant dans un état invalide ou incohérent. Un avantage supposé de l'encapsulation est qu'elle peut réduire la complexité du système, et donc augmenter la robustesse , en permettant au développeur de limiter les interdépendances entre les composants logiciels.

Certains langages comme Smalltalk et Ruby n'autorisent l'accès que via des méthodes objet, mais la plupart des autres (par exemple, C++ , C# , Delphi ou Java ) offrent au programmeur un degré de contrôle sur ce qui est caché, généralement via des mots-clés comme publicet private. La norme ISO C++ fait référence à protected, privateet en publictant que " spécificateurs d'accès " et qu'ils ne "cachent aucune information". Le masquage des informations est réalisé en fournissant une version compilée du code source qui est interfacé via un fichier d'en-tête.

Presque toujours, il existe un moyen de contourner une telle protection - généralement via l' API de réflexion (Ruby, Java, C#, etc.), parfois par un mécanisme tel que la modification des noms ( Python ) ou l'utilisation de mots clés spéciaux comme frienden C++. Les systèmes qui fournissent une sécurité basée sur les capacités au niveau objet (adhérant au modèle de capacité objet ) sont une exception et garantissent une encapsulation forte.

Exemples

Restriction des champs de données

Des langages comme C++ , C# , Java , PHP , Swift et Delphi offrent des moyens de restreindre l'accès aux champs de données.

Vous trouverez ci-dessous un exemple en C# qui montre comment l'accès à un champ de données peut être restreint via l'utilisation d'un privatemot - clé :

class Program
{
    public class Account
    {
        private decimal accountBalance = 500.00m;

        public decimal CheckBalance()
        {
            return this.accountBalance;
        }
    }

    static void Main()
    {
        Account myAccount = new Account();
        decimal myBalance = myAccount.CheckBalance();

        /* This Main method can check the balance via the public
         * "CheckBalance" method provided by the "Account" class 
         * but it cannot manipulate the value of "accountBalance" */
    }
}

Ci-dessous un exemple en Java :

public class Employee {
    private BigDecimal salary = new BigDecimal(50000.00);
    
    public BigDecimal getSalary() {
        return this.salary;
    }

    public static void main() {
        Employee e = new Employee();
        BigDecimal sal = e.getSalary();
    }
}

L'encapsulation est également possible dans les langages non orientés objet. En C par exemple, une structure peut être déclarée dans l'API publique via le fichier d'en-tête pour un ensemble de fonctions qui opèrent sur une donnée contenant des données membres non accessibles aux clients de l'API avec le externmot clé.

// Header file "api.h"

struct Entity;          // Opaque structure with hidden members

// API functions that operate on 'Entity' objects
extern struct Entity *  open_entity(int id);
extern int              process_entity(struct Entity *info);
extern void             close_entity(struct Entity *info);
// extern keywords here are redundant, but don't hurt.
// extern defines functions that can be called outside the current file, the default behavior even without the keyword

Les clients appellent les fonctions API pour allouer, opérer et désallouer des objets d'un type de données opaque . Les contenus de ce type ne sont connus et accessibles qu'à la mise en œuvre des fonctions API ; les clients ne peuvent pas accéder directement à son contenu. Le code source de ces fonctions définit le contenu réel de la structure :

// Implementation file "api.c"

#include "api.h"

struct Entity {
    int     ent_id;         // ID number
    char    ent_name[20];   // Name
    ... and other members ...
};

// API function implementations
struct Entity * open_entity(int id)
{ ... }

int process_entity(struct Entity *info)
{ ... }

void close_entity(struct Entity *info)
{ ... }

Nom mutilant

Vous trouverez ci-dessous un exemple de Python , qui ne prend pas en charge les restrictions d'accès aux variables. Cependant, la convention est qu'une variable dont le nom est préfixé par un trait de soulignement doit être considérée comme privée.

class Car: 
    def __init__(self) -> None:
        self._maxspeed = 200
 
    def drive(self) -> None:
        print(f"Maximum speed is {self._maxspeed}.")
 
redcar = Car()
redcar.drive()  # This will print 'Maximum speed is 200.'

redcar._maxspeed = 10
redcar.drive()  # This will print 'Maximum speed is 10.'

Voir également

Les références