Estaba leyendo esta página , sobre cuándo se justifican los captadores / establecedores, y el OP dio el siguiente ejemplo de código:
class Fridge
{
int cheese;
void set_cheese(int _cheese) { cheese = _cheese; }
int get_cheese() { return cheese; }
}
void go_shopping(Fridge fridge)
{
fridge.set_cheese(fridge.get_cheese() + 5);
}
La respuesta aceptada dice:
Por cierto, en su ejemplo, le daría a la clase
Fridge
los métodosputCheese()
ytakeCheese()
, en lugar deget_cheese()
yset_cheese()
. Entonces todavía tendrías encapsulación.
¿Cómo se preserva la encapsulación al renombrarla de get / set a putCheese()
/ takeCheese()
Obviamente está obteniendo / estableciendo un valor, entonces, ¿por qué no simplemente dejarlo como get / set?
En la misma respuesta también dice:
Tener captadores y establecedores no rompe en sí mismo la encapsulación. Lo que rompe la encapsulación es agregar automáticamente un getter y un setter para cada miembro de datos (cada campo, en la jerga de Java), sin pensarlo.
En este caso, solo tenemos una variable, cheese
y es posible que desee tomar y devolver el queso a la nevera, por lo que se justifica un par get / set en este caso.
fuente
putCheese
agregaría queso al refrigerador ytakeCheese
lo eliminaría: estas son abstracciones orientadas al dominio (de nivel superior), en lugar de captadores y establecedores de campos de objetos (que son abstracciones de programación de computadora (de bajo nivel)).Respuestas:
Creo que te estás perdiendo el punto. No significa que debas cambiar el nombre del setter y getter, sino tener métodos que agreguen y retiren elementos del refrigerador. es decir
Ahora la variable privada está encapsulada. No puedo configurarlo para lo que quiera, solo puedo agregar y quitar lonchas de queso de la nevera utilizando los métodos, lo que a su vez garantiza que se apliquen las reglas lógicas comerciales de queso que quiera.
fuente
setCheese()
que tiene la misma lógica en el setter. Para mí, de todos modos, estás tratando de ocultar el hecho de que estás usando un setter cambiando el nombre del método, pero obviamente obtienes / configura algo.AddCheese(Integer.MAX_VALUE)
debería fallar, pero no lo hará.Getters y setters rompen la encapsulación cada vez , por definición. Lo que podría argumentarse es que a veces necesitamos hacer eso. Con eso fuera del camino, aquí están mis respuestas:
La diferencia está en la semántica, es decir, el significado de lo que escribes. La encapsulación no se trata solo de proteger, sino de ocultar el estado interno. El estado interno ni siquiera debería conocerse en el exterior, sino que se espera que el objeto ofrezca métodos relevantes para el negocio (a veces denominado "comportamiento") para manipular / usar ese estado.
Por lo tanto
get
, yset
son los términos técnicos y parecen no tener nada que ver con el dominio "nevera", mientras queput
ytake
en realidad podría tener algún sentido.Sin embargo , si
put
otake
hacer real sentido sigue dependiendo de los requisitos y no se puede juzgar objetivamente. Ver siguiente punto:Eso no puede determinarse objetivamente sin más contexto. Su ejemplo contiene un
go_shopping()
método en otro lugar. Si eso es para lo queFridge
sirve, entonces no necesitaget
oset
, lo que necesita esFridge.go_shopping()
. De esta manera, tiene un método que se deriva de los requisitos, todos los "datos" que necesita son locales y tiene un comportamiento real en lugar de una estructura de datos apenas velada.Recuerde, no está creando un genérico, reutilizable
Fridge
. Está construyendo un soloFridge
para sus requisitos. Cualquier esfuerzo dedicado a hacerlo más de lo que debe ser es realmente un desperdicio.fuente
Getters and setters break encapsulation every single time
- Eso está demasiado redactado para mi gusto. Los métodos (incluidos getters y setters) tienen el mismo propósito que las puertas en un concierto: permiten la entrada y salida ordenadas del lugar.public int getFoo()
, es casi imposible, en la práctica, cambiar a otro tipo.Casi todo esto muestra un malentendido fundamental de la encapsulación y cómo se aplica.
La respuesta inicial de que estaba rompiendo la encapsulación es incorrecta. Es posible que su aplicación necesite simplemente establecer el valor del queso en el refrigerador en lugar de aumentar / disminuir o agregar / eliminar. Además, no es semántica, no importa cómo lo llame, si necesita acceder y / o cambiar atributos, no interrumpe la encapsulación al proporcionarlos. Finalmente, la encapsulación no se trata realmente de "esconderse", se trata de controlar el acceso al estado y los valores que no deberían ser públicos o manipulados fuera de la clase, al tiempo que se los otorga a aquellos que deberían hacerlo y realizar la tarea disponible internamente.
Un getter o setter no rompe la encapsulación cuando existe una necesidad legítima de obtener o establecer un valor. Es por eso que los métodos pueden hacerse públicos.
La encapsulación se trata de mantener los datos y los métodos que modifican esos datos directamente juntos en un lugar lógico, la clase.
En este caso particular, existe claramente la necesidad de cambiar el valor del queso en la aplicación. Independientemente de cómo se haga esto, a través de get / set o add / remove, siempre que los métodos estén encapsulados en la clase, está siguiendo el estilo orientado a objetos.
Para aclarar, daré un ejemplo de cómo se rompe la encapsulación al proporcionar acceso independientemente del nombre del método o la ejecución lógica.
Digamos que su refrigerador tiene una "vida útil", solo una serie de tics antes de que el refrigerador deje de estar operativo (por el argumento, el refrigerador no puede repararse). Lógicamente, no hay forma de que un usuario (o el resto de su aplicación) pueda cambiar este valor. Debería ser privado. Solo sería visible a través de decir un atributo público diferente conocido como "isWorking". Cuando expira la vida útil, internamente el refrigerador se pone a trabajar en falso.
La ejecución de la cuenta regresiva de por vida y su activación del interruptor isWorking es todo interno en el refrigerador, nada afuera podría / debería ser capaz de afectar el proceso. isWorking solo debe ser visible, por lo tanto, un captador no rompe la encapsulación. Sin embargo, agregar accesores para elementos del proceso de por vida rompería su encapsulación.
Como la mayoría de las cosas, la definición de encapsulación no es literal, es relativa. ¿Deberías poder ver X fuera de la clase? ¿Deberías poder cambiar Y? ¿Es todo lo que se aplica a su objeto aquí en esta clase o la funcionalidad se extiende a través de múltiples clases?
fuente
No se trata solo de renombrar un método. Los dos métodos funcionan de manera diferente.
(Imagina esto en tu mente)
get_cheese y set_cheese expone el queso. putCheese () y takeCheese () mantienen el queso oculto y se encarga de administrarlo y le dan al usuario una forma de manejarlo. El observador no ve el queso, solo ve dos métodos para manipularlo.
fuente