En los sistemas de software, la encapsulación se refiere a la agrupación de datos con los mecanismos o métodos que operan sobre los datos. También puede referirse a la limitación del acceso directo a algunos de esos datos, como los componentes de un objeto. [1] Esencialmente, la encapsulación evita que el código externo se preocupe por el funcionamiento interno de un objeto.
La encapsulación permite a los desarrolladores presentar una interfaz consistente que es independiente de su implementación interna. Como ejemplo, la encapsulación se puede utilizar para ocultar los valores o el estado de un objeto de datos estructurados dentro de una clase , impidiendo el acceso directo a ellos por parte de los clientes de una manera que podría exponer detalles de implementación ocultos o violar la invariancia de estado mantenida por los métodos.
También anima a los programadores a poner todo el código relacionado con un determinado conjunto de datos en la misma clase, lo que lo organiza para que otros programadores lo comprendan fácilmente. La encapsulación es una técnica que fomenta el desacoplamiento .
Todos los sistemas de programación orientada a objetos (POO) admiten la encapsulación, [2] [3] pero la encapsulación no es exclusiva de la POO. Las implementaciones de tipos de datos abstractos , módulos y bibliotecas , entre otros sistemas, también ofrecen encapsulación. La similitud ha sido explicada por los teóricos del lenguaje de programación en términos de tipos existenciales . [4]
En los lenguajes de programación orientados a objetos y otros campos relacionados, la encapsulación se refiere a una de dos nociones relacionadas pero distintas y, a veces, a la combinación de las mismas: [5] [6]
Algunos investigadores y académicos de lenguajes de programación utilizan el primer significado solo o en combinación con el segundo como una característica distintiva de la programación orientada a objetos , mientras que algunos lenguajes de programación que proporcionan cierres léxicos ven la encapsulación como una característica del lenguaje ortogonal a la orientación a objetos.
La segunda definición está motivada por el hecho de que en muchos lenguajes orientados a objetos y otros campos relacionados, los componentes no se ocultan automáticamente y esto puede anularse; por lo tanto, quienes prefieren la segunda definición definen el ocultamiento de información como una noción separada.
Las funciones de encapsulación se admiten mediante clases en la mayoría de los lenguajes orientados a objetos, aunque también existen otras alternativas.
Los autores de Design Patterns analizan extensamente la tensión entre herencia y encapsulación y afirman que, según su experiencia, los diseñadores abusan de la herencia. Afirman que la herencia a menudo rompe la encapsulación, dado que la herencia expone una subclase a los detalles de la implementación de su padre. [10] Como se describe en el problema yo-yo , el uso excesivo de la herencia y, por lo tanto, la encapsulación, puede volverse demasiado complicado y difícil de depurar.
Según la definición de que la encapsulación "puede usarse para ocultar miembros de datos y funciones miembro", la representación interna de un objeto generalmente está oculta a la vista fuera de la definición del objeto. Normalmente, sólo los métodos propios del objeto pueden inspeccionar o manipular directamente sus campos. Ocultar las partes internas del objeto protege su integridad al evitar que los usuarios establezcan los datos internos del componente en un estado no válido o inconsistente. Un supuesto beneficio de la encapsulación es que puede reducir la complejidad del sistema y, por tanto, aumentar la robustez , al permitir al desarrollador limitar las interdependencias entre los componentes del software. [ cita necesaria ]
Algunos lenguajes como Smalltalk y Ruby sólo permiten el acceso a través de métodos de objetos, pero la mayoría de los demás (por ejemplo, C++ , C# , Delphi o Java [11] ) ofrecen al programador un grado de control sobre lo que está oculto, normalmente mediante palabras clave como public
y private
. [8] El estándar ISO C++ se refiere a protected
y private
como public
" especificadores de acceso " y que no "ocultan ninguna información". La ocultación de información se logra proporcionando una versión compilada del código fuente que se interconecta a través de un archivo de encabezado.
Casi siempre, hay una manera de anular dicha protección, generalmente a través de la API de reflexión (Ruby, Java, C#, etc.), a veces mediante mecanismos como la alteración de nombres ( Python ) o el uso de palabras clave especiales como friend
en C++. Los sistemas que proporcionan seguridad basada en capacidades a nivel de objetos (que se adhieren al modelo de capacidad de objetos ) son una excepción y garantizan una encapsulación sólida.
Lenguajes como C++ , C# , Java , [11] PHP , Swift y Delphi ofrecen formas de restringir el acceso a los campos de datos.
A continuación se muestra un ejemplo en C# que muestra cómo se puede restringir el acceso a un campo de datos mediante el uso de una private
palabra clave:
programa de clase { cuenta de clase pública { saldo de cuenta decimal privado = 500,00 m ; saldo de cuenta decimal público () { return _accountBalance ; } } static void Main () { Cuenta miCuenta = nueva Cuenta (); decimal miSaldo = miCuenta . ComprobarSaldo (); /* Este método principal puede verificar el saldo a través del * método público "CheckBalance" proporcionado por la clase "Account" * pero no puede manipular el valor de "accountBalance" */ } }
A continuación se muestra un ejemplo en Java :
Empleado de clase pública { salario BigDecimal privado = nuevo BigDecimal ( 50000,00 ); public BigDecimal getSalary () { devolver esto . salario ; } public static void main () { Empleado e = nuevo Empleado (); BigDecimal sal = e . obtenerSalario (); } }
La encapsulación también es posible en lenguajes no orientados a objetos. En C , por ejemplo, se puede declarar una estructura en la API pública a través del archivo de encabezado para un conjunto de funciones que operan en un elemento de datos que contiene miembros de datos a los que no pueden acceder los clientes de la API con la extern
palabra clave. [12]
// Archivo de encabezado "api.h"estructura Entidad ; // Estructura opaca con miembros ocultos // API functions that operate on 'Entity' objectsextern struct Entity * open_entity(int id);extern int process_entity(struct Entity *info);extern void close_entity(struct Entity *info);// extern keywords here are redundant, but don't hurt.// extern defines functions that can be called outside the current file, the default behavior even without the keyword
Clients call the API functions to allocate, operate on, and deallocate objects of an opaque data type. The contents of this type are known and accessible only to the implementation of the API functions; clients cannot directly access its contents. The source code for these functions defines the actual contents of the structure:
// Implementation file "api.c"#include "api.h"struct Entity { int ent_id; // ID number char ent_name[20]; // Name ... and other members ...};// API function implementationsstruct Entity * open_entity(int id){ ... }int process_entity(struct Entity *info){ ... }void close_entity(struct Entity *info){ ... }
Below is an example of Python, which does not support variable access restrictions. However, the convention is that a variable whose name is prefixed by an underscore should be considered private.[13]
class Car: def __init__(self) -> None: self._maxspeed = 200 def drive(self) -> None: print(f"Maximum speed is {self._maxspeed}.") redcar = Car()redcar.drive() # This will print 'Maximum speed is 200.'carro rojo . _maxspeed = 10 coche rojo . drive () # Esto imprimirá 'La velocidad máxima es 10'.
Los mecanismos de encapsulación permiten al programador agrupar datos y las subrutinas que operan sobre ellos en un solo lugar, y ocultar detalles irrelevantes a los usuarios de una abstracción.