Introducción: «¿Por qué no simplemente hacer los campos public?»
\n\nImagina la situación: estás escribiendo una clase Person en Java. Tiene nombre, edad y email. La forma más sencilla es declarar los campos como public y acceder a ellos directamente:
public class Person {\n public String name;\n public int age;\n public String email;\n}\n\n«¡Funciona! —dirás—. ¿Para qué necesito esos getters y setters? Código extra, las líneas se alargan…»
\n\nEsta pregunta es una de las más populares en Stack Overflow. Miles de desarrolladores, especialmente principiantes, se la hacen. La respuesta que obtendrás de un programador Java experimentado será breve: encapsulación. Pero detrás de esta palabra se esconde toda una filosofía de diseño que salva proyectos del caos.
\n\nEn este artículo no solo daremos una definición. Analizaremos los problemas reales que resuelven los getters y setters (también llamados accessors y mutators), y lo mostraremos con código real. ¡Allá vamos!
\n\n1. Encapsulación: no solo una palabra de moda
\n\nEncapsulación es un principio de la POO que dice: oculta la estructura interna del objeto y proporciona una interfaz controlada para interactuar con él. Los getters y setters son precisamente esa interfaz controlada.
\n\nCompara los dos enfoques:
\n\nEnfoque malo (campos public)
\nPerson person = new Person();\nperson.age = -5; // ¿Edad negativa? ¡Fácil!\nperson.email = "not-an-email"; // Datos basura pasan sin verificación\n\nEnfoque bueno (getters y setters)
\npublic class Person {\n private String name;\n private int age;\n private String email;\n\n public int getAge() {\n return age;\n }\n\n public void setAge(int age) {\n if (age < 0 || age > 150) {\n throw new IllegalArgumentException("La edad debe estar entre 0 y 150");\n }\n this.age = age;\n }\n\n public String getEmail() {\n return email;\n }\n\n public void setEmail(String email) {\n if (email == null || !email.contains("@")) {\n throw new IllegalArgumentException("Email no válido");\n }\n this.email = email;\n }\n\n // otros getters/setters...\n}\n\nAhora, si alguien intenta establecer la edad en -5, el programa lanzará una excepción. Los datos están protegidos. Ahí está el poder de la encapsulación.
\n\n2. Validación de datos sobre la marcha
\n\nLos setters son el lugar ideal para verificar los datos de entrada. Sin ellos, tendrías que escribir la validación en cada lugar donde asignes un valor. Eso es duplicación de código y el riesgo de olvidar verificar en algún sitio.
\n\nEjemplo con una cuenta bancaria:
\n\npublic class BankAccount {\n private double balance;\n\n public double getBalance() {\n return balance;\n }\n\n public void deposit(double amount) {\n if (amount <= 0) {\n throw new IllegalArgumentException("El monto del depósito debe ser positivo");\n }\n this.balance += amount;\n }\n\n public void withdraw(double amount) {\n if (amount <= 0) {\n throw new IllegalArgumentException("El monto del retiro debe ser positivo");\n }\n if (amount > balance) {\n throw new IllegalStateException("Fondos insuficientes");\n }\n this.balance -= amount;\n }\n}\n\nObserva: aquí no hay un setter directo para balance. Gestionamos el saldo a través de los métodos deposit y withdraw, que ya contienen toda la lógica de verificación. El getter simplemente devuelve el estado actual.
3. Flexibilidad: puedes cambiar la implementación sin romper el código
\n\nImagina que almacenas la edad en un campo int, y luego decides almacenar la fecha de nacimiento y calcular la edad dinámicamente. Si tenías
Blogs
Book Recommendations
Leer también
Seguridad de aplicaciones Kotlin: top 10 vulnerabilidades en la práctica
CI/CD para Go: creando un pipeline desde cero en 20 minutos
Cómo no abandonar Python al empezar: guía para principiantes
Clean Code en C++: principios y ejemplos para principiantes
instanceof en Java: ¿es necesaria la comprobación de null? Análisis bajo el capó