Programación Orientada a Objetos: Encapsulamiento

5 minuto(s) de lectura

Este Post es la cuarta parte de la serie “Programación Orientada a Objetos”. Esta serie tiene como objetivo establecer los fundamentos de la POO, utilizando Java como ejemplo. Los temas de esta serie son los siguientes:

  1. Definición de POO
  2. Clases y Objetos
  3. Herencia
  4. Abstracción
  5. Encapsulamiento
  6. Polimorfismo
  7. Composición
  8. Principios utilizados en la POO

Todo el código de la serie está disponible en GitHub.

El código correspondiente a esta cuarta parte lo pueden encontrar aquí.

Todos los ejemplos están hechos en Netbeans.

Introducción

Otro de los conceptos principales de la POO es el encpsulamiento. Ya hemos venido aplicando el encapsulamiento desde que comenzamos a hablar acerca de los objetos. Encapsular significa envolver todos los datos y comportamientos en un solo lugar. Esto es lo que buscamos al crear objetos: tener los datos y comportamientos comunes en un solo objeto.

Así mismo, el encapsulamiento busca limitar la interacción que puedan tener objetos externos sobre nuestro objeto, esto con el objetivo de que los datos de nuestro objeto se encuentren seguros y no puedan ser cambiados en cualquier momento y por cualquier otro objeto. Esto se logra escondiendo las variables y los métodos de nuestro objeto para limitar su interacción externa.

El encapsulamiento ya lo habíamos aplicado antes. Viendo nuestro ejemplo de Usuario (en el proyecto POO), vemos que declaramos nuestras variables privadas

private String nombre;
private String apellido;
private int edad;
private String email;

y posteriormente creamos métodos públicos, llamados getters y setters, para poder modificar estas variables.

public void setNombre(String nombre) {
    this.nombre = nombre;
}

public String getNombre() {
    return nombre;
}

public void setApellido(String apellido) {
    this.apellido = apellido;
}

public String getApellido() {
    return apellido;
}

public void setEdad(int edad) {
    this.edad = edad;
}

public int getEdad() {
    return edad;
}

public void setEmail(String email) {
    this.email = email;
}

public String getEmail() {
    return email;
}

Con esto logramos encapsular las variables de la clase Usuario y obligamos a otros objetos externos a utilizar los métodos para modificar los valores de las variables de Usuario.

Lo que se quiere lograr con el encapsulamiento, es hacer de cada objeto una caja negra, que solamente puedan tener opción de ingresar valores para sus variables y obtener los resultados de vuelta. Así, aun cuando el objeto tenga más variables que solamente sean de uso interno, los objetos externos no tendrán conocimiento de su existencia y no las podrán modificar, asegurando el buen funcionamiento del comportamiento del objeto en cuestión.

Niveles de Acceso

Para poder implementar el encapsulamiento de una manera adecuada, Java nos provee varios niveles de acceso para nuestras variables y métodos. Dependiendo del nivel de acceso que tengan, estas variables y métodos podrán ser accesados y modificados por ciertos elementos.

private

Este es el nivel de acceso más limitado de todos. Las variables y métodos que sean declarados privados, solamente podrán ser accesados dentro de la clase. Teniendo como ejemplo nuestra clase Usuario y nuestras siguientes variables

private String nombre;
private String apellido;
private int edad;
private String email;

Si creamos un objeto usuario e intentamos acceder a estas variables, obtendremos un error diciendo que nombre tiene acceso privado.

Usuario usuario = new Usuario();
usuario.nombre = "Warrior Minds";

De igual manera, un método privado solamente puede ser accesado dentro de la clase en la que está declarado.

public

El nivel de acceso public da acceso a todo mundo a la variable o al método. Cualquiera que cree un objeto, puede tener acceso a estos métodos y variables. Es por eso que a nuestros métodos getters y setters son públicos.

public void setNombre(String nombre) {
    this.nombre = nombre;
}

public String getNombre() {
    return nombre;
}

Desde cualquier lado, podemos mandarlos llamar:

usuario.setNombre("Warrior Minds");
System.out.println(usuario.getNombre());

protected

El nivel de acceso protected se puede ver como un punto intermedio entre público y privado. Las variables o métodos protected podrán ser accesados dentro de la clase, dentro del mismo paquete y en clases hijas (sin importar en el paquete que se encuentren).

Si declaramos una variable protected

protected String direccion;

Y tratamos de usarla en nuestra clase Encapsulamiento, no la podemos utilizar.

usuario.direccion = "Calle central";

Esto pasa porque la clase Encapsulamiento está en el paquete com.warriorminds, y la clase Usuario está en el paquete com.warriorminds.encapsulamiento.

En cambio, si creamos otra clase dentro del paquete com.warriorminds.encapsulamiento, ahí sí podemos tener acceso a esta variable, como por ejemplo en la clase Prueba.

public class Prueba {

    public Prueba() {
        Usuario usuario = new Usuario();
        usuario.direccion = "Calle central 123";
    }
}

Si creamos una clase en un paquete diferente y que herede de la clase Usuario, también podremos tener acceso a la variable dirección.

public class OtroHijoDeUsuario extends Usuario {
    public OtroHijoDeUsuario() {
        direccion = "Mi nueva dirección";
    }
}

Declarando variables y métodos sin modificador de acceso

Tenemos la opción de NO indicar el tipo de acceso a una variable o método. Al hacer esto, nuestras variables y métodos podrán ser accesados desde dentro de su clase, y dentro del mismo paquete, pero NO podrán ser accesadas en clases hijas (a menos que estén en el mismo paquete).

Al declarar esta variable apodos en nuestra clase Usuario (dentro del paquete com.warriorminds.encapsulamiento)

List<String> apodos = new ArrayList<>();

La clase Prueba puede tener acceso a ella ya que están en el mismo paquete:

public Prueba() {
    Usuario usuario = new Usuario();
    usuario.apodos.add("El Warrior");
}

Igualmente, la clase HijoDeUsuario puede tener acceso a ella, ya que están en el mismo paquete también:

public HijoDeUsuario() {
    apodos.add("El Warrior");
}

Pero la clase Encapsulamiento NO puede tener acceso, porque están en diferente paquete.

usuario.apodos.add("Otro más");

De igual manera, nuestra clase OtroHijoDeUsuario, que hereda de Usuario, pero está en otro paquete, tampoco tiene acceso:

public class OtroHijoDeUsuario extends Usuario {
    public OtroHijoDeUsuario() {
        //apodos.add("Esto no es posible!");
    }
}

Conclusión

Es importante declarar el nivel de acceso adecuado a nuestras variables y métodos, para tener un diseño correcto de nuestro programa. En la siguiente tabla podemos ver un resumen de los modificadores de acceso que existen en Java, los cuales ayudan a implementar el encapsulamiento.

Modificador Clase Paquete Clase Hija Mundo
public
protected No
sin modificador No No
private No No No

Etiquetas:

Categorías:

Actualizado:

Deja un comentario