ООП не изобрел инкапсуляцию и не является синонимом инкапсуляции. Многие языки ООП не имеют модификаторов доступа в стиле C ++ / Java. Многие не-ООП языки имеют различные методы, доступные для инкапсуляции.
Один классический подход к инкапсуляции - это замыкания , используемые в функциональном программировании . Это значительно старше ООП, но в некотором смысле эквивалентно. Например, в JavaScript мы можем создать такой объект:
function Adder(x) {
this.add = function add(y) {
return x + y;
}
}
var plus2 = new Adder(2);
plus2.add(7); //=> 9
Вышеуказанный plus2
объект не имеет члена, который бы позволял прямой доступ к нему x
- он полностью инкапсулирован. add()
Метод представляет собой замыкание по x
переменной.
Язык C поддерживает некоторые виды инкапсуляции посредством механизма заголовочных файлов , в частности, метод непрозрачного указателя . В C можно объявить имя структуры без определения ее членов. На этом этапе нельзя использовать переменную типа этой структуры, но мы можем свободно использовать указатели на эту структуру (поскольку размер указателя структуры известен во время компиляции). Например, рассмотрим этот заголовочный файл:
#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
Теперь мы можем написать код, который использует этот интерфейс Adder, не имея доступа к его полям, например:
Adder plus2 = Adder_new(2);
if (!plus2) abort();
printf("%d\n", Adder_add(plus2, 7)); /* => 9 */
Adder_free(plus2);
И здесь будут полностью инкапсулированные детали реализации:
#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;
}
Существует также класс модульных языков программирования , который фокусируется на интерфейсах уровня модуля. Языковая семья ML, вкл. OCaml включает интересный подход к модулям, называемым функторами . ООП затмило и в значительной степени отнесено к модульному программированию, но многие предполагаемые преимущества ООП больше касаются модульности, чем объектной ориентации.
Также есть наблюдение, что классы в языках ООП, таких как C ++ или Java, часто используются не для объектов (в смысле сущностей, которые разрешают операции посредством позднего связывания / динамической диспетчеризации), а просто для абстрактных типов данных (где мы определяем открытый интерфейс, который скрывает детали внутренней реализации). В статье « Понимание абстракции данных» (Cook, 2009) обсуждается это различие более подробно.
Но да, во многих языках вообще нет механизма инкапсуляции. На этих языках члены структуры остаются открытыми. Самое большее, соглашение об именах будет препятствовать использованию. Например, я думаю, что у Паскаля не было полезного механизма инкапсуляции.