OOP non ha inventato l'incapsulamento e non è sinonimo di incapsulamento. Molti linguaggi OOP non hanno modificatori di accesso in stile C ++ / Java. Molte lingue non OOP hanno varie tecniche disponibili per offrire l'incapsulamento.
Un approccio classico per l'incapsulamento è chiusure , come usato nella programmazione funzionale . Questo è significativamente più vecchio di OOP ma è in un modo equivalente. Per esempio. in JavaScript potremmo creare un oggetto come questo:
function Adder(x) {
this.add = function add(y) {
return x + y;
}
}
var plus2 = new Adder(2);
plus2.add(7); //=> 9
L'oggetto plus2
sopra non ha un membro che consentirebbe l'accesso diretto a x
- è interamente incapsulato. Il metodo add()
è una chiusura sulla variabile x
.
Il linguaggio C supporta alcuni tipi di incapsulamento attraverso il suo meccanismo file header , in particolare la tecnica puntatore opaco . In C, è possibile dichiarare un nome struct senza definire i suoi membri. A quel punto non si può usare alcuna variabile del tipo di quella struttura, ma possiamo usare liberamente i puntatori a quella struttura (poiché la dimensione di un puntatore di una struct è nota al momento della compilazione). Ad esempio, considera questo file di intestazione:
#ifndef ADDER_H
#define ADDER_H
typedef struct AdderImpl *Adder;
Adder Adder_new(int x);
void Adder_free(Adder self);
int Adder_add(Adder self, int y);
#endif
Ora possiamo scrivere il codice che utilizza questa interfaccia di Adder, senza avere accesso ai suoi campi, ad esempio:
Adder plus2 = Adder_new(2);
if (!plus2) abort();
printf("%d\n", Adder_add(plus2, 7)); /* => 9 */
Adder_free(plus2);
E qui ci sono i dettagli di implementazione totalmente incapsulati:
#include "adder.h"
struct AdderImpl { int x; };
Adder Adder_new(int x) {
Adder self = malloc(sizeof *self);
if (!self) return NULL;
self->x = x;
return self;
}
void Adder_free(Adder self) {
free(self);
}
int Adder_add(Adder self, int y) {
return self->x + y;
}
Esiste anche la classe di linguaggi di programmazione modulari , incentrata sul livello di modulo interfacce. La famiglia linguistica ML incl. OCaml include un approccio interessante ai moduli chiamati functors . OOP ha messo in ombra e in gran parte integrato la programmazione modulare, ma molti presunti vantaggi di OOP sono più legati alla modularità che all'orientamento agli oggetti.
C'è anche l'osservazione che le classi nei linguaggi OOP come C ++ o Java spesso non sono usate per objects (nel senso di entità che risolvono le operazioni attraverso late binding / dynamic dispatch) ma semplicemente per tipi di dati astratti (dove definiamo un'interfaccia pubblica che nasconde i dettagli di implementazione interna). Il documento In Understanding Data Abstraction, Revisited (Cook, 2009) discute questa differenza in maggior dettaglio.
Ma sì, molte lingue non hanno alcun meccanismo di incapsulamento. In queste lingue, i membri della struttura sono lasciati pubblici. Al massimo, ci sarebbe una convenzione di denominazione che scoraggia l'uso. Per esempio. Penso che Pascal non abbia un utile meccanismo di incapsulamento.