2009-07-07 11 views
8

En las clases de Java, ¿se considera una buena o mala práctica acceder a los campos de miembros con sus getters y setters?¿Está en un anti-patrón usar siempre los métodos get y set para acceder a los campos de miembros de una clase?

por ejemplo, que es mejor:

public Order { 
    private Agreement agreement; 

    public Agreement getAgreement() { 
    return agreement; 
    } 

    public void process() { 
     //should I use: 
     getAgreement().doSomething(); 
     //Or: 
     agreement.doSomething(); 
    } 
} 

En general creo que el acceso al campo es directamente mejor debido al principio KISS y también alguien puede anular el método get más tarde con resultados impredecibles.

Sin embargo, mis colegas sostienen que es mejor mantener una capa de abstracción. ¿Hay algún consenso sobre esto?

+0

Del mismo modo, alguien puede anular getAgreement() y acceder al campo directamente lo rompe. –

+0

¿Por qué getAgreement() es público? Es difícil responder la pregunta sin saber eso. Si siempre defines getters públicos para todos los campos, entonces tendrás problemas mucho más grandes que decidir cómo escribir esa llamada a un método. – finnw

+0

posible duplicado de [Usando getters dentro de los métodos de clase] (http://stackoverflow.com/questions/629029/using-getters-within-class-methods), http://stackoverflow.com/questions/586087/when-should -a-class-use-its-own-getters-setters-vs-accessing-the-members-directl – nawfal

Respuesta

7

El problema central aquí es que el acceso directo al campo no es elegible para la interceptación por métodos reemplazados por subclase, AOP, proxies dinámicos y similares. Esto puede ser algo bueno o malo dependiendo del caso. Yo diría que usar getters y setters internamente no es un antipatrón o un patrón. Es algo bueno o malo según la situación y el diseño de tu clase.

7

Creo que la interfaz pública de una clase representa la encapsulación en torno al estado y, como tal, incluso las otras funciones de la clase se benefician de esa encapsulación.

Si ha envuelto un campo en un método de obtención pública, entonces hay una razón por la que lo ha hecho. Quizás exista una lógica dentro de ese método para cargar el campo de manera perezosa o proporcionar un seguimiento de auditoría. Cualquiera sea la razón del método, su clase probablemente también necesitará esa lógica.

+2

He visto problemas específicos cuando uso Hibernate para ORM. El código que usaba las variables directamente siempre obtenía valores nulos, el código que utilizaba los getters siempre funcionaba. Hibernate estaba suministrando una clase proxy para admitir la carga diferida. –

+0

John, ¿ese problema no surgiría solo si tiene las anotaciones de hibernación en el getter/setter? Puse las anotaciones en el campo de la clase y los documentos de hibernación dicen que hace que manipule el campo directamente. Hacer eso también le permite proporcionar getters sin setters ya que hibernate no los está usando. – lumpynose

+0

@lumpynose: Creo que hiberna el uso del acceso basado en campos o propiedades ortogonales a si genera clases proxy para la carga diferida. Hibernate aún puede usar el acceso de nivel de campo y requerir proxies para implementar la funcionalidad de carga lenta, activando los NPE que se obtienen si la carga diferida no se ejecuta correctamente en el acceso de campo. – Jherico

0

Para que sea un anti-patrón, tendría que ser decididamente perjudicial. No veo cómo puede haber daño en la definición de getters y setters. A lo sumo, es una pérdida de tiempo (y mecanografía), lo que lo hace inútil, pero no un antipatrón.

+0

Destruye la encapsulación. –

2

Mantener una capa de abstracción es algo bueno en Java.

El problema es que todo el código que accede directamente a las variables miembro sin que la clase lo note no está bajo el control de su clase.

Así que en el momento en que decida editar su clase de forma que un miembro que se utiliza en una división como ejemplo nunca debe ser 0, debe asegurarse de que este valor solo se modifique de forma que garantice esta. Por lo tanto, debería agregar un colocador para este método y cambiar el miembro a privado. Pero ahora necesita cambiar todo el código que está accediendo al miembro sin setter.
Si sabe que está cambiando el valor desde fuera de la clase y solo luego proporcione un setter si no sabe, haga que la variable sea privada y si necesita acceso más adelante quizás proporcione un getter o un setter.

Obtiene un Anti-Patrón si hay ciertos métodos en otros objetos que siempre están usando get para un miembro, luego realiza algunos cálculos y luego usa get. Esto muestra que el miembro debe estar en la otra clase o que el método debe estar en esta clase.

Tener un captador y un colocador sin pensarlo para cada miembro rompe la encapsulación y no es una buena opción de diseño. Para más información, lea esto article

9

Honestamente, en mi opinión, depende de para qué lo utilice. Personalmente, cuando tengo dudas, siempre dejo ese nivel extra de abstracción allí solo en caso de que necesite anularlo más adelante en una subclase. Muchas veces me he salvado del dolor de volver a escribir una clase solo porque dejé un getter o un setter abierto para anular.

Otra cosa es que otros clientes/programadores pueden necesitar usar su clase de una manera que aún no han pensado, por ejemplo, sacando la clase de Acuerdo de una base de datos. En ese caso, cuando anulan su clase, ha hecho que sea indolora para ellos (o posiblemente para un futuro) modificar cómo se recuperan esos datos.

Así que, a menos que esté absolutamente seguro de que solo hay una forma de acceder a ese campo, y que es 100% directo, probablemente sea mejor desacoplar la recuperación y modificación de valores para que en un futuro pueda salvarse de reescribir las dificultades.

0

Depende de para qué usa sus captadores y decodificadores. En general, los utilizo cuando necesito verificar la cordura de los datos que entran en una clase o dar formato a los datos que salen. En ese sentido, realmente uso getters y setters como una capa de interfaz entre esta clase y otras clases que pueden necesitar acceso a sus datos.

Tiendo a escribir mi código interno de modo que sepa cómo manejar datos privados para esta clase, por lo que acceder a él con sus propios getters y setters generalmente es innecesario y no deseado.

Sin embargo, todo depende de cómo uses tus getters y setters.

0

Mi regla de oro es que si hacen algo más complejo que simplemente establecer o devolver el valor, use los setters/getters. De lo contrario, no es necesario, ya que puede solucionar los problemas causados ​​por los cambios en las variables miembro.

+2

Pero la razón para usar sistemáticamente el captador y el colocador es que, si bien el captador/instalador no puede hacer nada más que obtener y establecer el valor * hoy *, puede que no sea cierto mañana. – nsayer

1

Ahora estoy trabajando en algo que me favorece: ahora estamos trasladando parte de nuestras propiedades a una "bolsa de propiedades", lo que significa que no puede simplemente hacer referencia a la variable. Entonces, además de cambiar el captador, tenemos que cambiar todos los lugares que hacen referencia a esa variable. Es algo a tener en cuenta.

+2

Ahora llamaría a un bolso de propiedad un antipatrón. Me trae a la mente un mapa de pares de valores de nombres donde los valores están sin tipo. Es una alternativa perezosa para tener un diseño de clase y te puede morder el culo. – Jherico

+0

En general, sí, es mejor almacenar los datos en variables. La razón por la cual estamos convirtiendo ahora es porque estamos transfiriendo nuestra aplicación para usar la tienda persistente de BlackBerry. Cuando se utiliza la tienda persistente, cada cambio en la estructura del objeto (agregar otra variable int) dañará los datos persistentes. Hay otras soluciones, pero encontramos que una bolsa de propiedades es la mejor opción para nosotros. En cualquier caso, esto es solo un ejemplo de una situación cuando cambian las formas de acceso variables. – Tamar

0

Tienes razón en que es molesto hacer todo ese trabajo extra para cada variable de atributo. ¿Por qué el lenguaje permite algo tan básico que nadie lo hace? Sin embargo, hay razones muy convincentes para no permitir el acceso directo a los atributos.

Prefiero el Principio de acceso unificado de Eiffel. Nunca se puede asignar a un atributo, y se accede a los atributos y funciones de la misma manera:

class EXAMPLE 
feature 
    variable: INTEGER 
    variable_function: INTEGER 
    do 
     result := 4 
    end 
    variable_two: INTEGER assign variable_assign 
    variable_assign (in: INTEGER) 
    do 
     variable_two := in 
    end 
end 

feature 
test 
local 
    test: EXAMPLE 
    value: INTEGER 
do 
    create test 
    value := test.variable -- Valid 
    value := test.variable_function -- Valid and same even though it's a function 
    test.variable := value -- Invalid 
    test.variable_two := value -- Valid, an explicit setter is defined 
end 
4

Me suena como algunas personas están interpretando esta cuestión como sobre los captadores y definidores que se utilizan externamente; mi interpretación de la pregunta de Pablojim fue que se trata de usarlos dentro de la clase, a diferencia de la clase que accede directamente a sus campos. (Que son privados.)

En esa luz, estoy con Jherico y patros; use acceso directo desde dentro de la clase a menos que haya alguna razón para no hacerlo.

+0

El problema es que la "razón para no hacerlo" podría pertenecer a algún otro desarrollador que use su biblioteca, en algún momento y lugar muy lejano. Anulan el acceso y la clase no funciona correctamente. Pasar por alto un acceso no final es un error. – erickson

+0

Es cierto. Supongo que no me preocupo tanto porque automáticamente agrego una declaración final a mi clase. Soy de la religión de que si una clase no tiene el modificador final debe ser una clase abstracta; fue diseñado desde el principio para ser subclasificado. Por supuesto, está ese problema de proxying y querer una clase no final y quizás el constructor no-arg agregó mess. – lumpynose

0

Creo que esto es algo que debe considerarse caso por caso. Usar un getter en todo el código de clase lo complica y probablemente lo hace un poco más lento. Sin embargo, también lo hace más extensible y reutilizable.

Lo que suelo hacer es utilizar el getter si puedo evitar cualquier motivo por el cual alguien quiera anular mi getter con otro. Si es algo tan básico y simple que nunca tendría sentido, generalmente no uso getters.

Si escribe su código para acceder a las variables sin el captador, considere hacer que la función getter sea "definitiva". De esa forma, nadie tratará de anular tu código y arrancarse el pelo preguntándose por qué no está funcionando.(Tenga en cuenta que los proxies de Spring e Hibernate pueden hacer que esto sea una mala idea.)

Cuestiones relacionadas