Acceso a objetos o variables a través de un intermediario

Este será un texto sobre la arquitectura de programas orientados a objetos. Es para aquellos que planean dedicarse seriamente al desarrollo.

En la programación orientada a objetos, gran parte se basa en objetos, «cajas» especiales de datos y funciones que funcionan en el programa como un todo. Internamente, los objetos pueden tener una estructura compleja, pero externamente tienen «controles» e «indicadores» por medio de los cuales interactúan otras partes del programa con estos objetos.

Por ejemplo, podemos imaginar que un automóvil es un objeto: internamente tiene muchas piezas complejas y conexiones entre ellas. Pero externamente es relativamente simple: volante, pedales, interruptores, faros, velocímetro, tacómetro, indicador de temperatura, nivel de combustible, etc. Para conducirlo no necesitamos conocer el funcionamiento interno del automóvil, basta con aprender lo básico de las funciones externas.

Uno de los conceptos de la POO es la encapsulación, y a menudo se aplica esta idea en ella:

El acceso a los datos internos de un objeto no puede obtenerse directamente, sino que se realiza a través de mecanismos especiales. Esto es necesario para que otras partes del programa no puedan alterar anormalmente el funcionamiento del objeto.

Si hablamos de un automóvil, los datos internos del objeto son el volumen de gasolina en mililitros que ingresa al motor en cada carrera de trabajo. El conductor no puede controlarlo directamente y poner tanta gasolina como quiera en el motor. En cambio, puede pisar el acelerador y el coche calculará por sí mismo la concentración de gasolina en la mezcla aire-combustible.

Dichos mecanismos de acceso a datos a través de un intermediario se denominan getters y setters.

¿Qué es un Getter y un Setter?

Estas palabras provienen del inglés get (obtener) y set (establecer).

La tarea de un getter es obtener datos sobre algo dentro de un objeto y transmitirlos al exterior. Por ejemplo, el conductor no puede mirar constantemente el depósito de combustible para ver cuánta gasolina queda. En cambio, el conductor observa el indicador de combustible que muestra cuánta gasolina queda en el depósito. El indicador de combustible es un getter: toma datos del objeto (el automóvil) y se los entrega a quien los solicitó (el conductor).

Un setter funciona de manera diferente: cambia los valores dentro de un objeto. En el ejemplo del automóvil, el pedal del acelerador es un setter: según la fuerza de la presión, cambia el volumen de inyección de combustible en el motor. Así, los fabricantes protegen el motor de situaciones anormales: incluso si se pisa el acelerador a fondo, una cantidad segura de combustible ingresará al motor.

Getters y Setters en Programación

Muy a menudo, en la programación, estas herramientas se utilizan como un método o interfaz de objeto: creas un objeto e indicas qué se puede hacer con él. Lo explicaremos con un ejemplo.

Supongamos que estamos haciendo una votación para una tienda en línea: las personas eligen si les gusta o no un determinado producto. Una de nuestras tareas es asegurarnos de que nada en el código del programa pueda influir directamente en el valor del contador. Todo lo que permitimos es incrementar el contador en uno o averiguar el valor actual. Esto nos librará de una situación en la que alguna función quiera incrementar repentinamente el contador a 10 mil votos.

Para hacerlo, basta con ocultar la variable del contador en un objeto y declarar dos métodos en él: lectura (descubrir el resultado) y escritura (votar, es decir, incrementar estrictamente en uno). Para ello, ni siquiera es necesario crear una clase separada. En JavaScript, por ejemplo, esto se puede hacer usando un cierre estándar cuando colocamos una función dentro de otra.

// Declaramos un nuevo objeto constante usando una función de flecha
const crearContador = () => {
  // El acceso a esta variable solo es posible dentro de esta función, no se puede cambiar desde fuera
  let contador = 0;

  // Qué devuelve la función
  return ({
    // Si se llama al método incrementar(), aumentamos la variable contador en 1
    incrementar: () => contador += 1,
    // Si se llama al método obtenerConteoVotos, devolvemos el valor del contador
    obtenerConteoVotos: () => contador.toLocaleString()
  });
};

// Creamos un nuevo objeto basado en el nuestro
const contador = crearContador();

// Hacemos clic un par de veces, aumentando el contador en uno
// No podremos cambiarlo de otra manera
contador.incrementar();
contador.incrementar();

// Observamos qué obtenemos al final (2)
console.log(contador.obtenerConteoVotos());

Y si intentamos cambiar el valor de la variable contador en el programa principal, nada cambiará. Y todo porque el acceso a la variable contador solo es posible desde dentro del objeto y solo de dos maneras permitidas.

// ❌ Parece que esto también funcionará, pero en realidad el valor del contador no cambiará
contador.contador = 100;
// El resultado seguirá siendo el número 2
console.log(contador.obtenerConteoVotos());

¿Para qué Sirven?

La principal tarea de los getters y setters es proteger los datos dentro del objeto para que cambien según sus propias reglas, no como quiera. En pocas palabras, son intermediarios que ven si es posible hacer algo con los datos o no. Si es posible, lo hacen, si no, no. Como resultado, los datos están seguros y el usuario tiene una herramienta para trabajar con ellos.

Serie de Guías Relacionadas a POO:

  1. Explicación Programación Orientada a Objetos
  2. ¿Qué son las Clases en Programación Orientada a Objetos?
  3. ¿Qué son los Objetos en Programación Orientada a Objetos?
  4. Clases y Funciones en Programación Orientada a Objetos
  5. Atributos y Métodos en Programación Orientada a Objetos
  6. Abstracciones e Interfaces: ¿Por qué son Necesarias?
  7. ¿Qué son los Getters y Setters en Programación?

Categorizado en:

Fundamentos,