OOP não inventou o encapsulamento e não é sinônimo de encapsulamento. Muitas linguagens OOP não possuem modificadores de acesso no estilo C ++ / Java. Muitas linguagens não OOP têm várias técnicas disponíveis para oferecer encapsulamento.
Uma abordagem clássica para encapsulamento é o fechamento , conforme usado na programação funcional . Isso é significativamente mais antigo que o OOP, mas é de certa forma equivalente. Por exemplo, em JavaScript, podemos criar um objeto como este:
function Adder(x) {
this.add = function add(y) {
return x + y;
}
}
var plus2 = new Adder(2);
plus2.add(7); //=> 9
O plus2
objeto acima não possui nenhum membro que permita acesso direto x
- é totalmente encapsulado. O add()
método é um fechamento sobre a x
variável.
A linguagem C suporta alguns tipos de encapsulamento através de seu mecanismo de arquivo de cabeçalho , particularmente a técnica de ponteiro opaco . Em C, é possível declarar um nome de estrutura sem definir seus membros. Nesse ponto, nenhuma variável do tipo dessa estrutura pode ser usada, mas podemos usar ponteiros para essa estrutura livremente (porque o tamanho de um ponteiro de estrutura é conhecido em tempo de compilação). Por exemplo, considere este arquivo de cabeçalho:
#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
Agora podemos escrever código que usa essa interface do Adder, sem ter acesso aos seus campos, por exemplo:
Adder plus2 = Adder_new(2);
if (!plus2) abort();
printf("%d\n", Adder_add(plus2, 7)); /* => 9 */
Adder_free(plus2);
E aqui estariam os detalhes de implementação totalmente encapsulados:
#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;
}
Há também a classe de linguagens de programação modulares , que se concentra nas interfaces no nível do módulo. A família de idiomas ML incl. OCaml inclui uma abordagem interessante para módulos chamados functors . OOP ofuscou e modificou amplamente a programação modular, mas muitas vantagens pretendidas do OOP têm mais a ver com modularidade do que com orientação a objetos.
Há também a observação de que classes em linguagens OOP como C ++ ou Java geralmente não são usadas para objetos (no sentido de entidades que resolvem operações através de ligação tardia / envio dinâmico), mas apenas para tipos de dados abstratos (onde definimos uma interface pública que oculta detalhes de implementação interna). O artigo Sobre a compreensão da abstração de dados, revisitado (Cook, 2009) discute essa diferença com mais detalhes.
Mas sim, muitos idiomas não possuem mecanismo de encapsulamento. Nesses idiomas, os membros da estrutura são deixados públicos. No máximo, haveria uma convenção de nomenclatura que desencorajaria o uso. Por exemplo, acho que Pascal não tinha um mecanismo de encapsulamento útil.