Inkapseling (computerprogrammering) - Encapsulation (computer programming)

In objectgeoriënteerd programmeren (OOP) verwijst inkapseling naar het bundelen van gegevens met de methoden die op die gegevens werken, of het beperken van directe toegang tot sommige componenten van een object. Inkapseling wordt gebruikt om de waarden of status van een gestructureerd gegevensobject binnen een klasse te verbergen , waardoor directe toegang door clients wordt voorkomen op een manier die verborgen implementatiedetails blootlegt of de statusinvariantie die door de methoden wordt onderhouden, schenden.

Openbaar toegankelijke methoden worden over het algemeen in de klasse aangeboden om de status abstracter te benaderen of te wijzigen. In de praktijk worden soms methoden (zogenaamde "getters" en "setters" ) verstrekt om indirect toegang te krijgen tot de waarden, maar hoewel ze niet noodzakelijk een schending van abstracte inkapseling zijn, worden ze vaak beschouwd als een wegwijzer van potentieel slechte objectgeoriënteerde programmering (OOP) ontwerppraktijk (een antipatroon ).

Dit mechanisme is niet uniek voor OOP. Implementaties van abstracte datatypes , bijv. modules , bieden een vergelijkbare vorm van inkapseling. De overeenkomst is verklaard door programmeertaaltheoretici in termen van existentiële typen .

Betekenis

In objectgeoriënteerde programmeertalen en andere gerelateerde velden verwijst inkapseling naar een van de twee gerelateerde maar verschillende begrippen, en soms naar de combinatie daarvan:

  • Een taalmechanisme voor het beperken van directe toegang tot sommige componenten van het object .
  • Een taalconstructie die het bundelen van gegevens met de methoden (of andere functies) die op die gegevens werken, vergemakkelijkt .

Sommige programmeertaalonderzoekers en academici gebruiken de eerste betekenis alleen of in combinatie met de tweede als een onderscheidend kenmerk van objectgeoriënteerd programmeren , terwijl sommige programmeertalen die lexicale afsluitingen bieden , inkapseling zien als een kenmerk van de taal die orthogonaal staat ten opzichte van objectoriëntatie.

De tweede definitie wordt gemotiveerd door het feit dat in veel objectgeoriënteerde talen en andere gerelateerde velden de componenten niet automatisch worden verborgen en dit kan worden overschreven; dus het verbergen van informatie wordt gedefinieerd als een apart begrip door degenen die de voorkeur geven aan de tweede definitie.

De kenmerken van inkapseling worden ondersteund met klassen in de meeste objectgeoriënteerde talen, hoewel er ook andere alternatieven bestaan.

Inkapseling en overerving

De auteurs van Design Patterns gaan uitgebreid in op de spanning tussen overerving en inkapseling en stellen dat ontwerpers naar hun ervaring overmatig gebruik maken van overerving. Ze beweren dat overerving vaak de inkapseling verbreekt, aangezien overerving een subklasse blootstelt aan de details van de implementatie van de bovenliggende klasse. Zoals beschreven door het jojo-probleem , kan overmatig gebruik van overerving en dus inkapseling te ingewikkeld en moeilijk te debuggen worden.

Informatie verbergen

Onder de definitie dat inkapseling "kan worden gebruikt om gegevensleden en lidfuncties te verbergen", wordt de interne representatie van een object over het algemeen aan het zicht onttrokken buiten de objectdefinitie. Gewoonlijk kunnen alleen de eigen methoden van het object de velden rechtstreeks inspecteren of manipuleren. Het verbergen van de interne onderdelen van het object beschermt de integriteit ervan door te voorkomen dat gebruikers de interne gegevens van het onderdeel in een ongeldige of inconsistente staat zetten. Een verondersteld voordeel van inkapseling is dat het de systeemcomplexiteit kan verminderen en dus de robuustheid kan vergroten , doordat de ontwikkelaar de onderlinge afhankelijkheden tussen softwarecomponenten kan beperken.

Sommige talen, zoals Smalltalk en Ruby, bieden alleen toegang via objectmethoden, maar de meeste andere (bijv. C++ , C# , Delphi of Java ) bieden de programmeur een zekere mate van controle over wat er verborgen is, meestal via trefwoorden zoals publicen private. ISO C++-standaard verwijst naar protected, privateen publicals " toegangsspecificaties " en dat ze "geen informatie verbergen". Het verbergen van informatie wordt bereikt door een gecompileerde versie van de broncode te leveren die is gekoppeld via een headerbestand.

Bijna altijd is er een manier om dergelijke bescherming te overschrijven - meestal via de reflectie- API (Ruby, Java, C#, enz.), soms door een mechanisme zoals naamverwisseling ( Python ), of speciaal trefwoordgebruik zoals friendin C ++. Systemen die op capaciteit gebaseerde beveiliging op objectniveau bieden (volgens het objectcapaciteitsmodel ) vormen een uitzondering en garanderen een sterke inkapseling.

Voorbeelden

Gegevensvelden beperken

Talen zoals C++ , C# , Java , PHP , Swift en Delphi bieden manieren om de toegang tot gegevensvelden te beperken.

Hieronder ziet u een voorbeeld in C# dat laat zien hoe de toegang tot een gegevensveld kan worden beperkt door het gebruik van een privatetrefwoord:

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" */
    }
}

Hieronder een voorbeeld in 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();
    }
}

Inkapseling is ook mogelijk in niet-objectgeoriënteerde talen. In C kan bijvoorbeeld een structuur worden gedeclareerd in de openbare API via het headerbestand voor een set functies die werken op een data-item dat dataleden bevat die niet toegankelijk zijn voor clients van de API met het externtrefwoord.

// 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

Clients roepen de API-functies aan om objecten van een ondoorzichtig gegevenstype toe te wijzen, erop te werken en de toewijzing ongedaan te maken . De inhoud van dit type is alleen bekend en toegankelijk voor de implementatie van de API-functies; klanten hebben geen directe toegang tot de inhoud ervan. De broncode voor deze functies definieert de feitelijke inhoud van de structuur:

// 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)
{ ... }

Naam mangelen

Hieronder ziet u een voorbeeld van Python , dat geen variabele toegangsbeperkingen ondersteunt. De afspraak is echter dat een variabele waarvan de naam wordt voorafgegaan door een onderstrepingsteken, als privé moet worden beschouwd.

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.'

Zie ook

Referenties