JavaRush /Blog Java /Random-ES /Captadores y definidores

Captadores y definidores

Publicado en el grupo Random-ES
¡Hola! En conferencias anteriores, ya aprendió cómo crear sus propias clases completas, con campos y métodos. Este es un gran progreso, ¡bien hecho! Pero ahora tengo que contarles una verdad desagradable. ¡No creamos nuestras clases del todo bien! ¿Por qué? A primera vista, no hay errores en esta clase:
public class Cat {

   public String name;
   public int age;
   public int weight;

   public Cat(String name, int age, int weight) {
       this.name = name;
       this.age = age;
       this.weight = weight;
   }

   public Cat() {
   }

   public void sayMeow() {
       System.out.println("¡Maullar!");
   }
}
De hecho, lo hay. Imagina que mientras estás sentado en el trabajo escribiste una clase como esta Cat, que denota gatos. Y se fue a casa. Mientras estabas fuera, otro programador vino a trabajar, creó su propia clase Main, donde comenzó a usar la clase que escribiste Cat.
public class Main {

   public static void main(String[] args) {

       Cat cat = new Cat();
       cat.name = "";
       cat.age = -1000;
       cat.weight = 0;
   }
}
No importa por qué lo hizo ni cómo sucedió: tal vez la persona estaba cansada o no durmió lo suficiente. Otra cosa es importante: nuestra clase actual Catte permite asignar valores locos a los campos. Como resultado, el programa contiene objetos con un estado incorrecto, como este gato con una edad de -1000 años. ¿Qué error terminamos cometiendo? Cuando creamos la clase, expusimos sus datos. Campos namey ageson weightde dominio público. Se puede acceder a ellos desde cualquier parte del programa: basta con crear un objeto Caty listo, cualquier programador tiene acceso a sus datos directamente a través del operador " ."
Cat cat = new Cat();
cat.name = "";
Aquí accedemos directamente al campo namey establecemos su valor. Necesitamos proteger de alguna manera nuestros datos de interferencias externas incorrectas. ¿Qué se necesita para esto? Primero, todas las variables de instancia (campos) deben marcarse con un modificador private. Privado es el modificador de acceso más estricto en Java. Si lo usa, los campos de la clase Catno serán accesibles fuera de ella.
public class Cat {

   private String name;
   private int age;
   private int weight;

   public Cat(String name, int age, int weight) {
       this.name = name;
       this.age = age;
       this.weight = weight;
   }

   public Cat() {
   }

   public void sayMeow() {
       System.out.println("¡Maullar!");
   }
}

public class Main {

   public static void main(String[] args) {

       Cat cat = new Cat();
       cat.name = "";//¡error! ¡El campo de nombre en la clase Cat tiene acceso privado!
   }
}
El compilador ve esto e inmediatamente produce un error. Ahora los campos parecen estar protegidos. Pero resulta que el acceso a ellos está “estrictamente” cerrado: el programa ni siquiera puede medir el peso de un gato existente, si es necesario. Esto tampoco es una opción: de esta forma nuestra clase es prácticamente imposible de usar. Idealmente, debemos permitir algún tipo de acceso limitado a los datos:
  • Otros programadores deberían poder crear objetos.Cat
  • Deberían poder leer datos de objetos ya existentes (por ejemplo, obtener el nombre o la edad de un gato ya existente).
  • También debería ser posible asignar valores de campo. Pero al mismo tiempo, sólo valores correctos. Nuestros objetos deben estar protegidos de los incorrectos (nada de “edad = -1000 años” y cosas por el estilo).
¡La lista de requisitos es decente! Pero, de hecho, todo esto se logra fácilmente utilizando métodos especiales: captadores y definidores .
Captadores y definidores - 2
El nombre proviene del inglés " get " - " recibir " (es decir, "método para obtener el valor de un campo") y set - " set " (es decir, "método para establecer el valor de un campo"). Veamos cómo se ven usando nuestra clase como ejemplo Cat:
public class Cat {

   private String name;
   private int age;
   private int weight;

   public Cat(String name, int age, int weight) {
       this.name = name;
       this.age = age;
       this.weight = weight;
   }

   public Cat() {
   }

   public void sayMeow() {
       System.out.println("¡Maullar!");
   }

   public String getName() {
       return name;
   }

   public void setName(String name) {
       this.name = name;
   }

   public int getAge() {
       return age;
   }

   public void setAge(int age) {
       this.age = age;
   }

   public int getWeight() {
       return weight;
   }

   public void setWeight(int weight) {
       this.weight = weight;
   }
}
Como puede ver, todo es bastante simple :) Sus nombres suelen consistir en la palabra get/set + el nombre del campo del que son responsables. Por ejemplo, un método getWeight()devuelve el valor del campo weightdel objeto para el que fue llamado. Así es como se ve en el programa:
public class Main {

   public static void main(String[] args) {

       Cat barsik = new Cat("Barsik", 5, 4);
       String barsikName = barsik.getName();
       int barsikAge = barsik.getAge();
       int barsikWeight = barsik.getWeight();

       System.out.println("Nombre del gato:" + barsikName);
       System.out.println("Edad del gato: " + barsikAge);
       System.out.println("Peso del gato: " + barsikWeight);
   }
}
Salida de consola:

Nombre кота: Барсик
Возраст кота: 5
Вес кота: 4
Ahora desde otra clase( Main) hay acceso a los campos Cat, pero sólo a través de getters . Tenga en cuenta que los captadores tienen un modificador de acceso public, lo que significa que son accesibles desde cualquier parte del programa. ¿Qué pasa con la asignación de valores? Los métodos de establecimiento son responsables de esto.
public void setName(String name) {
   this.name = name;
}
Su trabajo, como ves, también es sencillo. Llamamos a un método setName()en un objeto Cat, le pasamos una cadena como argumento y esta cadena se asigna a un campo namede nuestro objeto.
public class Main {

   public static void main(String[] args) {

       Cat barsik = new Cat("Barsik", 5, 4);

       System.out.println("El nombre original del gato es" + barsik.getName());
       barsik.setName("Albahaca");
       System.out.println("El nuevo nombre del gato -" + barsik.getName());
   }
}
Aquí utilizamos captadores y definidores. Primero, usando un captador, recibimos y enviamos a la consola el nombre inicial del gato. Luego, utilizando un definidor, namese asignó un nuevo valor a su campo: "Vasily". Y luego, usando un captador, obtuvimos el nombre nuevamente para verificar si realmente cambió. Salida de consola:

Изначальное Nombre кота — Барсик
Новое Nombre кота — Васoй
Al parecer, ¿cuál es la diferencia? También podemos asignar valores incorrectos a campos de objetos, incluso si tenemos definidores:
public class Main {

   public static void main(String[] args) {

       Cat barsik = new Cat("Barsik", 5, 4);
       barsik.setAge(-1000);

       System.out.println("Era de Barsik -" + barsik.getAge() + " años");
   }
}
Salida de consola:

Возраст Барсика — -1000 лет
La diferencia es que un setter es un método completo . Y en un método, a diferencia de un campo, puede colocar la lógica de verificación que necesita para evitar valores inaceptables. Por ejemplo, puedes desactivar fácilmente la asignación de un número negativo como edad:
public void setAge(int age) {
   if (age >= 0) {
       this.age = age;
   } else {
       System.out.println("¡Error! ¡La edad no puede ser negativa!");
   }
}
¡Y ahora nuestro código funciona correctamente!
public class Main {

   public static void main(String[] args) {

       Cat barsik = new Cat("Barsik", 5, 4);
       barsik.setAge(-1000);

       System.out.println("Era de Barsik -" + barsik.getAge() + " años");
   }
}
Salida de consola:

Ошибка! Возраст не может быть отрицательным числом!
Возраст Барсика — 5 лет
Hay una restricción dentro del configurador y protege contra intentos de establecer datos incorrectos. La edad de Barsik se mantuvo sin cambios. Siempre se deben crear captadores y definidores. Incluso si sus campos no tienen restricciones sobre los valores posibles, no causarán ningún daño. Imagine una situación: usted y sus colegas están escribiendo un programa juntos. Creaste una clase Catcon campos públicos y todos los programadores los usan como quieren. Y entonces, un buen día, te das cuenta: “¡Maldita sea, tarde o temprano alguien podría asignar accidentalmente un número negativo a una variable weight! ¡Necesitamos crear configuradores y hacer que todos los campos sean privados! Los creas y todo el código escrito por tus colegas se rompe instantáneamente. Después de todo, ya habían escrito un montón de código mediante el cual accedían Catdirectamente a los campos.
cat.name = "Hipopótamo";
¡Y ahora los campos se han vuelto privados y el compilador produce un montón de errores!
cat.name = "Hipopótamo";//¡error! ¡El campo de nombre de la clase Cat tiene acceso privado!
En tal situación, sería mejor ocultar los campos y crear getter-setters desde el principio . Todos sus colegas los usarían, y si se diera cuenta tarde de que necesitaba limitar los valores de los campos, simplemente agregaría una marca dentro del configurador. Y nadie rompería el código ya escrito. Por supuesto, si desea acceso de solo lectura a un campo determinado, puede crear un captador para él. “Afuera”, es decir, fuera de su clase, sólo deberían estar disponibles los métodos. Los datos deben estar ocultos.
Captadores y definidores - 4
Se puede hacer una analogía con un teléfono móvil. Imagínese que en lugar de un teléfono móvil normal encendido, le dieron un teléfono con la carcasa abierta, donde están todos los cables, circuitos, etc. sobresaliendo. El teléfono funciona: si te esfuerzas y jugueteas con los diagramas, es posible que incluso puedas hacer una llamada. Pero probablemente lo rompas. En cambio, la empresa fabricante le proporciona una interfaz: el cliente simplemente marca los números requeridos, presiona el botón verde con el teléfono y comienza la llamada. Y no le importa lo que sucede dentro con los circuitos y cables y cómo realizan su tarea. En este ejemplo, la empresa ha limitado el acceso a las "partes internas" (datos) del teléfono y ha dejado fuera sólo la interfaz (métodos). Como resultado, el cliente obtendrá lo que desea (hará una llamada) y definitivamente no romperá nada del interior.
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION