A questão principal aqui é que o encapsulamento não é um conceito rigidamente definido nem por que é útil. Fazer uma pesquisa mostra que a maneira como as pessoas veem o encapsulamento é altamente opinativa e que muitas pessoas o confundem com Abstração.
A primeira definição que você vai encontrar é
Encapsulamento é um conceito que une os dados e funções que manipulam os dados ...
Se essa é sua definição, a maioria das linguagens tem como agrupar dados e funções que operam nesses dados em classes, módulos, bibliotecas, espaços para nome, etc.
Mas eu argumentaria que esse não é o principal objetivo do encapsulamento, pois essa definição continua:
... e isso mantém os dois protegidos contra interferências externas e uso indevido.
A Wikipedia também concorda com isso:
Um mecanismo de linguagem para restringir o acesso direto a alguns dos componentes do objeto.
Mas agora, precisamos perguntar o que se entende por "interferência e uso indevido" e por que o acesso direto aos dados deve ser restrito. Eu acredito que há duas razões.
Primeiro, o escopo limitador no qual os dados podem ser mutados é do melhor interesse do desenvolvedor. Com muita frequência, é necessário ter lógica antes / depois do valor ser definido. E ter apenas um número limitado de locais onde o valor pode ser definido é extremamente valioso. Nos idiomas OOP, isso pode ser feito usando classes. Em linguagens funcionais "mutáveis", os fechamentos servem ao mesmo propósito. E porque sabemos que classes = fechamentos , é até discutível que linguagens funcionais mutáveis sejam um "paradigma" diferente do OOP.
Mas e as línguas imutáveis? Não tem problema de alterar variáveis. É aqui que entra a segunda questão: funções e dados de ligação permitem manter esses dados em um estado válido. Imagine que você tem uma estrutura imutável Email
. Essa estrutura possui um único string
campo. Temos requisitos para que, se você tiver um valor do tipo Email
, esse campo contenha um endereço válido. No encapsulamento da OOP, isso é facilmente feito declarando esse campo private
, fornecendo apenas Get
método e tendoconstructor method
que só será bem-sucedido se passado na cadeia de caracteres for um endereço válido. Coisa semelhante com fechamentos. Agora, para uma linguagem imutável, seria necessário dizer que a estrutura só pode ser inicializada através de uma função específica e essa função pode falhar. E não conheço nenhum idioma que se encaixe nesse critério (talvez alguém nos comentários possa me esclarecer).
Última edição é o que se entende por encapsulamento de "suporte" da linguagem. Por um lado, existem idiomas que permitem impor o encapsulamento, para que o código não seja compilado se o encapsulamento estiver quebrado. Por outro lado, o idioma pode fornecer uma maneira de encapsular, mas não o aplica, deixando o desenvolvedor aplicá-lo. Para o segundo caso, qualquer linguagem que possua estruturas e funções pode funcionar. Linguagens dinâmicas e Haskell vêm à mente. E eu diria que não há muitas línguas que caem do outro lado do espectro. Mesmo o C #, que é realmente bom em impor o encapsulamento para seus objetos, pode ser ignorado usando reflexão. Mas, vendo que em C # seria considerado um cheiro de código maciço e nenhum desenvolvedor de C # sano faria isso de bom grado.