2010-06-02 20 views
20

Soy nuevo en la programación. Ahora estoy aprendiendo Java, hay algo de lo que no estoy realmente seguro, que es el uso de lo privado. Por qué el programador estableció la variable como privada, luego escribe, obtiene y establece para acceder a ella. Por qué no poner todo en público ya que lo usamos de todos modos.el uso de la palabra clave privada

public class BadOO { 
    public int size; 

    public int weight; 
    ... 
} 

public class ExploitBadOO { 
    public static void main (String [] args) { 
     BadOO b = new BadOO(); 
     b.size = -5; // Legal but bad!! 
    } 
} 

Encontré un código como este, y vi el comentario legal pero malo. No entiendo por qué, por favor explícame.

Respuesta

17

La razón principal para no solo hacer que la variable sea pública en primer lugar es que si la hiciera pública, crearía más dolores de cabeza más adelante.

Por ejemplo, un programador escribe getters y setters públicos alrededor de una variable de miembro privada. Tres meses después, necesita verificar que la variable nunca se "establece" como nula. Agrega un cheque en el método "setFoo (...)", y todos los intentos de establecer la variable se verificarán para "configurarlo en nulo". Caso cerrado, y con poco esfuerzo.

Otro programador se da cuenta de que poner getters y setters públicos alrededor de una variable de miembro privado está violando el espíritu de encapsulación, ve la inutilidad de los métodos y decide hacer pública la variable miembro. Tal vez esto aumente un poco el rendimiento, o quizás el programador solo quiera "escribirlo tal como se usa". Tres meses después, necesita verificar que la variable nunca se "establece" como nula. Escanea todos los accesos a la variable, buscando efectivamente a través de la base de códigos completa, incluyendo todos los códigos que podrían acceder a la variable a través de la reflexión. Esto incluye todas las bibliotecas de terceros que han extendido su código, y todos los módulos recientemente escritos que usaron su código después de haber sido escrito. Luego modifica todas las llamadas para garantizar que la variable nunca se establezca como nula. El caso nunca se cierra, porque no puede encontrar efectivamente todos los accesos al miembro expuesto, ni tiene acceso a todos los códigos fuente de terceros. Con un conocimiento imperfecto de los módulos recién escritos, se garantiza que la encuesta estará incompleta. Finalmente, no tiene control sobre el código futuro que puede acceder al miembro público, y ese código puede contener líneas que establecen la variable miembro como nula.

Por supuesto, el segundo programador podría romper todos los códigos existentes poniendo métodos "get" y "set" alrededor de la variable y haciéndola privada, pero hey, podría haberlo hecho tres meses antes y haberse guardado la explicación de por qué necesitaba romper el código de todos los demás.

Llámelo como lo desee, pero poner métodos públicos de "obtener" y "establecer" en torno a una variable miembro privada es una programación defensiva que se ha llevado a cabo por muchos años (es decir, décadas) de experiencia.

+0

También facilita la depuración, ya que puede agregar registros o puntos de interrupción o lo que sea dentro de sus getters y setters. – Brian

22

El motivo más importante es ocultar los detalles de implementación interna de su clase. Si evita que los programadores confíen en esos detalles, puede modificar la implementación de manera segura sin preocuparse de romper el código existente que usa la clase.

Por lo tanto, al declarar el campo como privado, impide que un usuario acceda directamente a la variable. Al proporcionar gettters y setters, usted controla exactamente cómo un usuario puede controlar la variable.

+4

+1 para una respuesta que se entrega en un nivel apropiado para el asker – Catchwa

1

No debe permitir que las implementaciones alteren sus registros directamente. Proporcionar getters y setters significa que tienes control exacto sobre cómo se asignan las variables o qué se devuelve, etc. Lo mismo ocurre con el código en tu constructor. ¿Qué sucede si el colocador hace algo especial cuando asigna un valor al tamaño? Esto no sucederá si lo asigna directamente.

1

Es un problema frecuente de muchos programadores: código Java con campos private y accesos y mutadores public. El efecto es como dices, esos campos también podrían ser public.

Existen lenguajes de programación que también se expresan en el otro extremo. Mira Python; casi todo es público, hasta cierto punto.

Estas son prácticas de codificación diferentes y una cosa común que los programadores tratan todos los días. Pero en Java, aquí está mi regla de oro:

  • Si el campo es utilizada exclusivamente como un atributo, tanto de lectura y escritura por cualquier persona, que sea public.
  • Si el campo se usa solo internamente, use private. Proporcione un getter si desea acceso de lectura y proporcione un setter si desea acceso de escritura.
  • Hay un caso especial: a veces, desea procesar datos adicionales cuando se accede a un atributo. En ese caso, proporcionaría tanto getters como setters, pero dentro de estas funciones de propiedad, haría más que solo return; por ejemplo, si desea rastrear el número de veces que un atributo es leído por otros programas durante la vida de un objeto .

Esto es solo una breve descripción de los niveles de acceso. Si está interesado, también lea en el acceso protected.

+1

"Si el campo se usa únicamente como un atributo, tanto legible como escribible por cualquier persona, hágalo público.". Totalmente en desacuerdo; una vez que haga un campo publc olvídese de cambiar I. X – Pierreten

+0

¿Cambiando I.X? De todos modos, este tipo de práctica depende del idioma, y ​​puedes estar en desacuerdo. –

+1

No hay nada de malo con los atributos públicos, siempre que quede claro cómo se usarán. En Java no ocurre mucho, pero otros idiomas tienen vistas ligeramente diferentes. C# es bueno porque puedes cambiar un atributo a un par get (/ set) más tarde con el mismo nombre. –

4

Se considera malo principalmente porque pierdes el control sobre quién puede cambiar el valor y qué sucede cuando cambia el valor.

En una pequeña aplicación escrita por usted para usted, no parecerá tan importante, pero a medida que comience a desarrollar aplicaciones cada vez más grandes, tendrá control sobre quién cambia qué y cuándo se vuelve crítico.

Imagina de tu ejemplo anterior, publicas la biblioteca como es, otras personas la usan, luego decides que querías calcular otro valor en tu clase mala cuando cambia el tamaño ... de repente la clase bad00 no tiene forma de saber y no puedes cambiarlo porque otras personas dependen de él.

En cambio, si usted tenía un método set se podría extender con decir

void SetSize(int newSize) 
{ 
    size = newSize; 
    DoCalculation; 
} 

puede ampliar la funcionalidad sin romper la dependencia de otras personas en usted.

0

Los programadores de C# lo utilizan tanto o más frecuentemente que lo que veo en Java. C# lo llama propiedades donde en Java es accessors/mutators

Para mí tiene sentido tener métodos getter y setter para encapsular las clases de modo que ninguna clase pueda cambiar las variables de instancia de otra clase.

+2

C# tiene soporte real para las propiedades y admite el principio de acceso uniforme http://en.wikipedia.org/wiki/Uniform_access_principle que hace que trabajar con propiedades sea menos complicado que en Java. – Jesper

+0

Gracias por el artículo Jesper; Siempre he tenido ese concepto en mente cuando uso propiedades, pero ahora tengo una etiqueta para él. – Pierreten

5

Cualquier cosa pública en su clase es un contrato con los usuarios de la clase. Al modificar la clase, debe mantener el contrato. Puede agregar al contrato (nuevos métodos, variables, etc.), pero no puede eliminarlo. Lo ideal sería que ese contrato sea lo más pequeño posible. Es útil hacer todo lo privado que puedas. Si necesita acceso directo de los miembros del paquete, hágalo protegido. Solo haga públicas esas cosas que requieren sus usuarios.

La exposición de variables significa que se está contrayendo para siempre, tener esa variable y permitir que los usuarios la modifiquen. Como se discutió anteriormente, puede encontrar que necesita invocar el comportamiento cuando se accede a una variable. Esto se puede hacer si solo contratas los métodos getter y setter.

Muchas de las primeras clases de Java tienen contratos que requieren que sean seguras para hilos. Esto agrega una sobrecarga significativa en los casos donde solo un hilo puede acceder a la instancia. Las versiones más nuevas tienen nuevas clases que duplican o mejoran la funcionalidad, pero eliminan la sincronización. De ahí que se haya agregado StringBuilder y en la mayoría de los casos se debe usar en lugar de StringBuffer.

-4

Depende de quién acceda a estas variables públicas. Muy probablemente, solo por personas dentro de su compañía/equipo. Entonces es trivial refactorizarlos en getters/setters cuando sea necesario. Digo en este caso, es mejor dejar las variables públicas; a menos que te obliguen a seguir la convención de Java Bean.

Si está escribiendo un marco o una biblioteca destinada al público, entonces no debe exponer las variables. Es imposible para usted cambiarlos en getters/setters más tarde.

Pero el segundo caso es más raro que el primero; la gente aplica supuestos extremadamente irracionales cuando se trata de un ingeniero de software, como si no estuvieran escribiendo código, sino que están grabando el código en piedra. Y como si todo el mundo estuviera mirando mientras codificas - en realidad, nadie leerá tu código excepto tú mismo

+1

No estoy de acuerdo. Su código no es solo leído por usted mismo, si trabaja en un equipo adecuado. ¿Alguna vez has probado las evaluaciones por pares y la programación de pares? –

+3

No sé cuánto experiencia de desarrollo de software en el mundo real tiene, irrebatible; pero solo como anécdota, actualmente tengo que agregar nuevas características al código escrito hace 6 años por un desarrollador que aparentemente tiene su mentalidad. Su código TENDRÁ vida propia una vez en producción. – Pierreten

1

De hecho, se usa para ocultar la implementación interna. Esto también ayuda a proporcionar un poco más de lógica en sus variables. Supongamos que necesita asegurarse de que el valor pasado para un valor variable no sea 0/nulo, puede proporcionar esta lógica en el método set. También de la misma manera puede proporcionar algo de lógica al obtener el valor, digamos que tiene una variable de objeto que no se inicializa y está accediendo a ese objeto, en este caso puede proporcionar la lógica para verificar nulo ese objeto y siempre devolver un objeto.

2

Recomiendo encarecidamente el libro Effective Java, contiene mucha información útil acerca de cómo escribir mejores programas en Java.

Su pregunta se aborda en los artículos 13 y 14 de ese libro:

  • Tema 13: Minimizar la accesibilidad de las clases y los miembros
  • artículo 14: En las clases públicas, usar métodos de acceso, campos no públicas
0

Bien. Estamos hablando de Objetos aquí. Los objetos del mundo real. Si no son privados, el usuario de su clase puede cambiar. ¿Qué pasa si para una clase Circle y para el atributo/propiedad de radio de la clase Circle, el usuario establece el valor como '0'. No tiene sentido que un círculo exista con radio como '0'. Puede evitar estos errores si convierte sus atributos en privados y le da un método setter y en el cual emite una excepción/error (instruyendo al usuario) de que no está permitido crear un círculo con radisu como '0'. Básicamente, los objetos que se crean a partir de su clase deben existir como desea que existan. Esta es una de las formas de lograrlo.

0

Como se dijo anteriormente, la razón para hacer que una variable sea privada es ocultarla desde el exterior. Pero si haces un getter Y un setter entonces también puedes hacer que la variable sea pública. Si luego te encuentras en una posición en la que tomaste la decisión incorrecta, entonces debes refactorizar tu código para que no use la variable pública y usar el getter/setter, que puede no ser un problema. Pero puede ser un problema si otro código, que no controlas, comienza dependiendo de tu código. Entonces tal refactorización romperá el otro código.Si usa getters y setters desde el principio, reducirá ese riesgo a cambio de un pequeño esfuerzo. Entonces depende de tu situación.

Cuestiones relacionadas