Inkapseling (Encapsulation)¶
Het idee achter OOP is dat methoden en eigenschappen toebehoren aan specifieke objecten (zie ook abstraction). Het moment dat je besluit om die eigenschappen en methoden onder te brengen in hun eigen class
, moet je ook garanties inbouwen dat die eigenschappen en methoden niet zomaar van buitenaf kunnen worden gewijzigd of aangeroepen.
Neem bijvoorbeeld de class
docent. Docenten hebben hun eigen eigenschappen en methoden: zo hebben ze een naam, leeftijd, en bepaalde gedragingen. Het zou gek zijn als iemand van buitenaf, zonder autorisatie, kan besluiten om een docent een andere naam te geven. Of als een student, zonder toestemming van de docent, besluit om cijfers in de cijferadministratie te wijzigen. Encapsulation garandeert dat die docent-eigenschappen, en de gedragingen, niet zomaar door anderen gebruikt kunnen worden.
Het OO-principe encapsulation (ook wel “inkapseling”) helpt je om je code op een georganiseerde en veilige manier te ontwerpen. Je verbergt interne details van classes en laat alleen de belangrijkste functionaliteit naar buiten zien. Dit maakt het gemakkelijker om je code te organiseren en te onderhouden.
Er zijn in drie vormen van bescherming:
- public: iedere class kan bij de parameter of method. Gebruik deze alleen als je zeker weet dat de parameter of method niet ‘beschermd’ moet worden van invloeden van buitenaf.
- private: alleen binnen de class kan deze parameter of method worden uitgelezen.
- protected: alleen binnen de class of de sub-class van deze (super-)class kan deze parameter of method worden uitgelezen.
In bepaalde programmeertalen kun je een attribute ‘beschermen’ door het woord private
of protected
ervoor te zetten.
In Python kan dit niet. Daarom is er een afspraak (of conventie) door middel van het gebruik van ‘underscores’.
- Als je een
protected
parameter of method aanmaakt plaats er dan een underscore (‘_‘, liggende streep) voor. Dan is het duidelijk dat het hier om een protected (en dus beschermde) attribute gaat. - Als je een
private
parameter of method aanmaakt plaats er dan twee underscores (‘__‘, liggende streep) voor. Dan is het duidelijk dat het hier om een private (en dus beschermde) attribute gaat.
Als je niet zeker weet of je tussen private
, protected
of public
moet kiezen… kies dan voor de beste bescherming: private
. Mocht je later toegang nodig hebben in andere class dan kun je dit altijd aanpassen naar protected
of public
.
Voorbeelden van Inkapseling in TypeScript en Python:
// super-class (or parent-class)
class Musician {
protected _artistName: string;
protected _bandName: string;
private _bankAccount: string;
public constructor(
artistName: string,
bandName: string,
bankAccount: string
) {
this._artistName = artistName;
this._bandName = bandName;
this._bankAccount = bankAccount;
}
public getArtistName(): string {
return this._artistName;
}
}
// sub-class (or child-class)
class Guitarist extends Musician {
public getBankAccount() {
//_bankAccount is a private parameter of the Musician class
// this will fail in the Guitarist sub-class (or child-class)
console.log("The bank account is ", this._bankAccount);
}
public getBandName() {
// _bandName is a protected parameter of the Musician class
// this will work in the Guitarist sub-class (or child-class)
console.log("The band name is ", this._bandName);
}
}
const guitarist: Guitarist = new Guitarist(
"Dan Auerbach",
"The Black Keys",
"ASNB123456790"
);
console.log(guitarist._bankAccount);
// fails because Property '_bankAccount' is private and only accessible within class 'Musician'.
console.log(guitarist._bandName);
// fails because property '_bandName' is protected and only accessible within class 'Musician' and its subclasses.
console.log(guitarist.getBandName());
// this will work because it is a public function
# super-class (or parent-class)
class Musician:
def __init__(self, artistName, bankAccount):
# protected
self._artistName = artistName
# private
self.__bankAccount = bankAccount
def play(self):
print("Musician plays. And this is his account:", self.__bankAccount )
def stop(self):
print("Musician stops. And this is his name:", self._artistName )
# sub-class (or child-class)
class Guitarist(Musician):
# private variable this will fail when uncommented
# def play(self):
# print("Guitarist plays. And this is his account:", self.__bankAccount )
# protected variable will be printed
def stop(self):
print("Guitarist plays. And this is his name is:", self._artistName )
musician = Musician('Animal', 'ASNB1213232212')
musician.play()
guitarist = Guitarist('Dirk', 'ASNB1213233312')
guitarist.play()
musician.stop()
guitarist.stop()
print(musician._artistName)
Zie het artikel over Access Modifiers voor meer informatie over de verschillende soorten bescherming.