Tengo una clase con una variable que es privada y la clase tiene un getter y un setter para esa variable. ¿Por qué no hacer pública esa variable?
El único caso que creo que tiene que usar getters y setters es si necesita hacer alguna operación además del set o get. Ejemplo:
void my_class::set_variable(int x){
/* Some operation like updating a log */
this->variable = x;
}
this->variable = x + 5
, o llamar a unaUpdateStatistics
función en setter, y en esos casosclassinstancea->variable = 5
causará problemas.set_inch
,set_centimeter
,get_inch
,get_centimeter
, con algunas acciones espeluznantes.Respuestas:
¿Alguna vez has oído hablar de una propiedad?
Una propiedad es un campo que tiene accesores "incorporados" (captadores y establecedores). Java, por ejemplo, no tiene propiedades, pero se recomienda escribir los captadores y definidores en un campo privado. C # tiene propiedades.
Entonces, ¿por qué necesitamos getters y setters? Básicamente lo necesitamos para proteger / proteger el campo. Por ejemplo, no está accediendo al campo en la referencia de memoria, está accediendo a un método que luego cambiará el campo (referencia). Ese método puede realizar algunas operaciones que un usuario no está dispuesto a conocer ( comportamiento de encapsulación ), como en su ejemplo. Imagine, por ejemplo, que una docena de clases usan su campo público y necesita cambiar la forma en que se usa ... Tendría que mirar cada una de esas clases para cambiar la forma en que usan el campo ... No entonces "OOlysh".
Pero, por ejemplo, si tiene un campo booleano llamado muerto. Debería pensarlo dos veces antes de declarar un setDead e isDead. Debería escribir accesores que sean legibles por humanos , por ejemplo, kill () en lugar de setDead.
Sin embargo, hay muchos marcos que suponen que está siguiendo la convención de nomenclatura JavaBean (hablando de Java aquí), por lo tanto, en esos casos, debe declarar todos los captadores y establecedores después de la convención de nomenclatura.
fuente
foo.bar = biz.baz+5
se llame a una funciónbiz
para evaluarbaz
, luego se agreguen cinco y se llame a una funciónfoo
para establecerbar
el valor resultante. Dichas sobrecargas no se denominan "propiedades", pero pueden servir para el mismo propósito.Esta no es la opinión más popular, pero no veo mucha diferencia.
Los setters y getters son una idea bastante mala. Lo he pensado y, sinceramente, no puedo encontrar una diferencia entre un setter / getter, una propiedad y una variable pública en la práctica.
En THEORY, un setter y getter o property agregan un lugar para tomar algunas acciones adicionales cuando se establece / obtiene una variable y, en teoría, aíslan su código de los cambios.
En realidad, rara vez veo setters y getters utilizados para agregar una acción, y cuando quieres agregar una acción, quieres agregarla a TODOS los setters o getters de una clase (como el registro), lo que debería hacerte pensar que debería Ser una mejor solución.
En cuanto a aislar las decisiones de diseño, si cambia un int a un largo todavía tiene que cambiar sus setters y al menos verificar cada línea que accede a ellas a mano, sin mucho aislamiento allí.
Las clases mutables deben evitarse de forma predeterminada de todos modos, por lo que agregar un setter debería ser el último recurso. Esto se mitiga con el patrón de construcción donde se puede establecer un valor hasta que el objeto esté en el estado deseado, entonces la clase puede volverse inmutable y sus establecedores generarán excepciones.
En cuanto a los captadores, todavía no puedo encontrar mucha diferencia entre un captador y una variable final pública. El problema aquí es que es malo OO en cualquier caso. No debería pedir un valor de un objeto y operarlo, debería pedirle a un objeto que haga una operación por usted.
Por cierto, no estoy abogando de ninguna manera por las variables públicas: digo que los establecedores y captadores (e incluso las propiedades) están demasiado cerca de ser variables públicas.
El gran problema es simplemente que las personas que no son programadores OO están demasiado tentados a usar setters y getters para convertir los objetos en bolas de propiedad (estructuras) que se transmiten y operan, casi todo lo contrario de cómo funciona el código orientado a objetos.
fuente
El usuario de getters y setters entra en el principio de encapsulación . Esto te permitirá cambiar cómo funcionan las cosas dentro de la clase y mantener todo funcionando.
Por ejemplo, si otros 3 objetos llaman
foo.bar
para obtener el valor de la barra y usted decide cambiar el nombre de la barra demasiado lejos, tiene un problema en sus manos. Si los objetos llamadosfoo.bar
tendrían que cambiar todas las clases que tienen esto. Si se usa un setter / getter, entonces no tiene nada que cambiar. Otra posibilidad es cambiar el tipo de la variable, en cuyo caso solo agregue un código de transformación al captador / definidor y estará bien.fuente
El uso de captadores y establecedores también le permite controlar qué contenido se almacena en una variable particular. Si el contenido debe ser de cierto tipo o valor, parte del código de establecimiento puede ser garantizar que el nuevo valor cumpla con estos requisitos. Si la variable es pública, no puede garantizar que se cumplan estos requisitos.
Este enfoque también hace que su código sea más adaptable y manejable. Es mucho más fácil hacer cambios en la arquitectura de una clase si tiene funciones que mantienen esa arquitectura oculta de todas las otras clases o funciones que utilizan esa clase. El cambio ya mencionado de un nombre de variable es solo uno de los muchos cambios que son mucho más fáciles de realizar si tiene funciones como getters y setters. La idea general es mantener la mayor privacidad posible, especialmente las variables de su clase.
fuente
Usted dice "El único caso que creo que tiene que usar getters y setters es si necesita hacer alguna operación además del set o el get".
Debe utilizar captadores y definidores si en algún momento en el futuro que puede ser que tenga que hacer alguna operación además del conjunto y obtener y no querer cambiar miles de líneas de código fuente cuando eso sucede.
Debe usar getters y setters si no desea que alguien tome la dirección de la variable y la pase, con consecuencias desastrosas si esa variable se puede cambiar sin ningún código fuente que lo mencione, o incluso después de que el objeto deje de existir. .
fuente
En primer lugar, seamos claros en el paradigma.
¿Dónde es útil un getter / setter?
¿Son útiles los getters / setters en las estructuras de datos? No.
Una estructura de datos es una especificación de diseño de memoria que es común y manipulada por una familia de funciones.
En general, cualquier función nueva y antigua puede aparecer y manipular una estructura de datos, si lo hace de una manera que las otras funciones aún puedan entenderla, entonces la función se une a la familia. De lo contrario, es una función maliciosa y una fuente de errores.
No me malinterpreten, podría haber varias familias de funciones que luchan sobre esa estructura de datos con soplones, revestimientos y agentes dobles en todas partes. Está bien cuando cada uno tiene su propia estructura de datos con la que jugar, pero cuando la comparten ... imagínense que varias familias del crimen no están de acuerdo con la política, puede convertirse en un desastre realmente rápido.
Dado el desorden que pueden lograr las familias de funciones extendidas, ¿hay alguna manera de codificar la estructura de datos para que las funciones no autorizadas no lo estropeen todo? Sí, se llaman objetos.
¿Son útiles los getters / setters en los objetos? No.
El objetivo de envolver una estructura de datos en un objeto era asegurar que no pudieran existir funciones deshonestas. Si la función quería unirse a la familia, primero tenía que ser examinada a fondo y luego convertirse en parte del objeto.
El objetivo / propósito de un getter y un setter es permitir que las funciones fuera del objeto alteren la disposición de la memoria del objeto directamente. Eso suena como una puerta abierta para permitir en pícaros ...
The Edge Case
Hay dos situaciones en las que un captador / colocador público tiene sentido.
Los contenedores y las interfaces de contenedor son ejemplos perfectos de estas dos situaciones. El contenedor gestiona las estructuras de datos (lista enlazada, mapa, árbol) internamente, pero controla el elemento específico a todos y cada uno. La interfaz resume esto e ignora la implementación por completo y describe solo las expectativas.
Desafortunadamente, muchas implementaciones se equivocan y definen la interfaz de este tipo de objetos para dar acceso directo al objeto real. Algo como:
Esto está descompuesto. Las implementaciones de Container deben entregar explícitamente el control de sus componentes internos a quien los use. Todavía no he visto un lenguaje de valor mutable en el que esto esté bien (los lenguajes con semántica de valor inmutable están bien por definición desde una perspectiva de corrupción de datos, pero no necesariamente desde una perspectiva de espionaje de datos).
Puede mejorar / corregir los captadores / establecedores utilizando solo semántica de copia o utilizando un proxy:
Podría decirse que una función deshonesta aún podría jugar al caos aquí (con suficiente esfuerzo, la mayoría de las cosas son posibles), pero la semántica de copia y / o proxy reduce la posibilidad de una serie de errores.
Getters / Setters privados
Este es el último bastión de getters y setters que trabajan directamente en el tipo. De hecho, ni siquiera llamaría a estos captadores y establecedores sino a accesores y manipuladores.
En este contexto, a veces manipular una porción específica de la estructura de datos siempre / casi siempre / generalmente requiere que se lleve una contabilidad específica. Supongamos que cuando actualiza la raíz de un árbol, la memoria caché de lado necesita ser purgada, o cuando accede al elemento de datos externo, se necesita obtener / liberar un bloqueo. En estos casos, tiene sentido aplicar el principal DRY y agrupar esas acciones juntas.
Dentro del contexto privado, todavía es posible que las otras funciones de la familia eluden a estos 'captadores y establecedores' y manipulen la estructura de datos. Por eso pienso en ellos más como accesores y manipuladores. Puede acceder a los datos directamente o confiar en otro miembro de la familia para que esa parte sea correcta.
Getters / Setters Protegidos
En un contexto protegido, no es terriblemente diferente a un contexto público. Las funciones extrañas posiblemente deshonestas desean acceder a la estructura de datos. Entonces no, si existen operan como captadores / setters públicos.
fuente
Desde la experiencia C ++, el setter / getter es útil para 2 escenarios:
Aparte de eso, la seguridad es un punto válido, pero su importancia se limita a muy pocas aplicaciones de desarrollo, como los módulos relacionados con el inicio de sesión o el acceso db. ¿Por qué molestarse en codificar más cuando solo unas pocas personas usan su módulo?
fuente