¿Cómo accedería a las propiedades del objeto desde un método de objeto? [cerrado]

96

¿Cuál es la forma "purista" o "correcta" de acceder a las propiedades de un objeto desde dentro de un método de objeto que no es un método getter / setter?

Sé que desde fuera del objeto deberías usar un getter / setter, pero desde dentro harías:

Java:

String property = this.property;

PHP:

$property = $this->property;

o harías:

Java:

String property = this.getProperty();

PHP:

$property = $this->getProperty();

Perdóname si mi Java está un poco mal, ha pasado un año desde que programé en Java ...

EDITAR:

Parece que la gente está asumiendo que estoy hablando solo de variables / propiedades privadas o protegidas. Cuando aprendí OO, me enseñaron a usar getters / setters para cada propiedad, incluso si era pública (y en realidad me dijeron que nunca hiciera pública ninguna variable / propiedad). Por lo tanto, puedo estar partiendo de una suposición falsa desde el principio. Parece que las personas que responden a esta pregunta tal vez estén diciendo que debería tener propiedades públicas y que esas no necesitan captadores y establecedores, lo que va en contra de lo que me enseñaron y de lo que estaba hablando, aunque tal vez eso deba discutirse como bien. Sin embargo, probablemente sea un buen tema para una pregunta diferente ...

cmcculloh
fuente

Respuestas:

62

Esto tiene un potencial de guerra religiosa, pero me parece que si estás usando un getter / setter, también deberías usarlo internamente; usar ambos conducirá a problemas de mantenimiento en el futuro (por ejemplo, alguien agrega código a un establecedor que necesita para ejecutar cada vez que se establece esa propiedad, y la propiedad se establece internamente sin que se llame a ese establecedor).

Greg Hurlman
fuente
no hace nada más en un setter que no sea establecer el valor de la propiedad, un ejemplo de uso incorrecto en Java.
euphoria83
1
@ euphoria83 Quizás, pero eso no impide que suceda.
Greg Hurlman
Estoy de acuerdo con la respuesta original. Sin embargo, solo recuerde que si está configurando u obteniendo algo privado dentro de la clase u objeto, debe asegurarse de que el getter / setter no sea cíclico o redundante de alguna manera que haga que su código falle. Si no puede usar el getter / setter, acceda directamente. (Ej. Su captador / configurador accede a un método secundario (privado / protegido) para manipular los datos).
Rick Mac Gillis
43

Personalmente, siento que es importante mantener la coherencia. Si tiene getters y setters, utilícelos. La única vez que accedería a un campo directamente es cuando el descriptor de acceso tiene mucha sobrecarga. Puede parecer que estás inflando tu código innecesariamente, pero ciertamente puede ahorrarte muchos dolores de cabeza en el futuro. El ejemplo clásico:

Más adelante, es posible que desee cambiar la forma en que funciona ese campo. Tal vez debería calcularse sobre la marcha o tal vez le gustaría usar un tipo diferente para la tienda de respaldo. Si accede a las propiedades directamente, un cambio como ese puede romper una gran cantidad de código de una sola vez.

MojoFilter
fuente
26

Estoy bastante sorprendido de lo unánime que es el sentimiento de que los gettersarmadores están bien y bien. Sugiero el artículo incendiario de Allen Holub " Getters And Setters Are Evil ". Por supuesto, el título es por valor de impacto, pero el autor hace puntos válidos.

Esencialmente, si tiene gettersy setterspara todos y cada uno de los campos privados, está haciendo que esos campos sean tan buenos como públicos. Sería muy difícil cambiar el tipo de campo privado sin efectos dominó en cada clase que lo llame getter.

Además, desde un punto de vista estrictamente orientado a objetos, los objetos deben responder a mensajes (métodos) que correspondan a su (con suerte) responsabilidad única. La gran mayoría de gettersy settersno tienen sentido para sus objetos constituyentes; Pen.dispenseInkOnto(Surface)tiene más sentido para mí que Pen.getColor().

Los captadores y definidores también alientan a los usuarios de la clase a pedir al objeto algunos datos, realizar un cálculo y luego establecer algún otro valor en el objeto, mejor conocido como programación procedimental. Sería mejor que le dijera simplemente al objeto que haga lo que iba a hacer en primer lugar; también conocido como el modismo Information Expert .

Los getters y setters, sin embargo, son males necesarios en el límite de las capas: UI, persistencia, etc. El acceso restringido a los elementos internos de una clase, como la palabra clave friend de C ++, el acceso protegido al paquete de Java, el acceso interno de .NET y el patrón de clase Friend pueden ayudarlo a reducir la visibilidad de gettersy los establecedores solo a aquellos que los necesitan.

moffdub
fuente
19

Depende de cómo se utilice la propiedad. Por ejemplo, supongamos que tiene un objeto de estudiante que tiene una propiedad de nombre. Puede usar su método Get para extraer el nombre de la base de datos, si aún no lo ha recuperado. De esta forma, reduce las llamadas innecesarias a la base de datos.

Ahora digamos que tiene un contador de enteros privado en su objeto que cuenta el número de veces que se ha llamado al nombre. Es posible que desee no utilizar el método Get desde el interior del objeto porque produciría un recuento no válido.

Shawn
fuente
Si el objeto de estudiante es un objeto de dominio / negocio, ahora está mezclando detalles de infraestructura. Idealmente, los objetos de dominio / negocio deberían preocuparse solo por la lógica de dominio / negocio.
moffdub
¿Qué pasa si agrega algún tipo de booleano al getter como: PHP: función pública getName ($ outsideCall = true) {if ($ outsideCall) {$ this-> incrementNameCalled (); } devolver $ este-> nombre; } y luego desde dentro del Objeto mismo, si llama a get name, puede evitar que se incremente mediante: PHP: $ name = $ this-> getName (false); ¿Me estoy yendo por la borda aquí?
cmcculloh
14

PHP ofrece una gran variedad de formas de manejar esto, incluidos los métodos mágicos __gety __set, pero prefiero captadores y definidores explícitos. Este es el por qué:

  1. La validación se puede colocar en setters (y getters para el caso)
  2. Intellisense trabaja con métodos explícitos
  3. No hay duda de si una propiedad es de solo lectura, solo escritura o lectura-escritura
  4. La recuperación de propiedades virtuales (es decir, valores calculados) tiene el mismo aspecto que las propiedades normales
  5. Puede establecer fácilmente una propiedad de objeto que nunca se define realmente en ningún lugar, que luego queda sin documentar
Carne sin etiqueta
fuente
13

¿Me estoy yendo por la borda aquí?

Quizás ;)

Otro enfoque sería utilizar un método privado / protegido para realizar la obtención (almacenamiento en caché / db / etc), y una envoltura pública que incremente el recuento:

PHP:

public function getName() {
    $this->incrementNameCalled();
    return $this->_getName();
}

protected function _getName() {
    return $this->name;
}

y luego desde dentro del propio objeto:

PHP:

$name = $this->_getName();

De esta manera, aún puede usar ese primer argumento para otra cosa (como enviar una bandera para indicar si se usarán o no datos almacenados en caché aquí).

pix0r
fuente
12

Debo estar perdiendo el punto aquí, ¿por qué usarías un captador dentro de un objeto para acceder a una propiedad de ese objeto?

Llevando esto a su conclusión, el captador debería llamar a un captador, que debería llamar a un captador.

Entonces, diría que dentro de un método de objeto acceder a una propiedad directamente, especialmente viendo que llamar a otro método en ese objeto (que simplemente accederá a la propiedad directamente de todos modos y luego lo devolverá) es solo un ejercicio inútil y derrochador (o he entendido mal la pregunta ).

Furgonetas de huevos
fuente
Me impulsó la misma necesidad que tuviste de comentar ... Además, se respondió no cerrado;)
Egg Vans
8

La forma más pura de OO es evitar ambas y seguir la Ley de Deméter utilizando el enfoque de Dile No Pregunte .

En lugar de obtener el valor de la propiedad del objeto, que empareja estrechamente las dos clases, use el objeto como parámetro, por ejemplo

  doSomethingWithProperty() {
     doSomethingWith( this.property ) ;
  }

Donde la propiedad era un tipo nativo, por ejemplo, int, use un método de acceso, asígnele el nombre del dominio del problema, no del dominio de programación.

  doSomethingWithProperty( this.daysPerWeek() ) ;

Estos le permitirán mantener la encapsulación y cualquier condición posterior o invariantes dependientes. También puede usar el método del setter para mantener cualquier condición previa o invariantes dependientes, sin embargo, no caiga en la trampa de nombrarlos setters, vuelva al Principio de Hollywood para nombrar cuando use el idioma.

Martín Spamer
fuente
8

Es mejor utilizar los métodos de acceso, incluso dentro del objeto. Estos son los puntos que me vienen a la mente de inmediato:

  1. Debe hacerse con el interés de mantener la coherencia con los accesos realizados desde fuera del objeto.

  2. En algunos casos, estos métodos de acceso podrían hacer algo más que acceder al campo; podrían estar haciendo algún procesamiento adicional (aunque esto es raro). Si este es el caso, acceder al campo directamente significaría que está perdiendo ese procesamiento adicional, y su programa podría fallar si este procesamiento siempre se realiza durante esos accesos.

Aadith Ramia
fuente
8

Si te refieres a "la mayoría de encapsulación" por "purista", entonces normalmente declaro todos mis campos como privados y luego uso "this.field" desde la propia clase. Para otras clases, incluidas las subclases, accedo al estado de la instancia utilizando los captadores.

Allain Lalonde
fuente
7

Descubrí que usar setters / getters hizo que mi código fuera más fácil de leer. También me gusta el control que da cuando otras clases usan los métodos y si cambio los datos, la propiedad almacenará.

Brendon-Van-Heyzen
fuente
7

Campos privados con propiedad pública o protegida. El acceso a los valores debe pasar por las propiedades y copiarse a una variable local si se usarán más de una vez en un método. Si y SOLAMENTE si tiene el resto de su aplicación totalmente ajustado, sacudido y optimizado de otra manera para que el acceso a los valores al pasar por sus propiedades asociadas se haya convertido en un cuello de botella (y eso nunca sucederá NUNCA, lo garantizo) en caso de que siquiera comience considerar permitir que cualquier otra cosa que no sean las propiedades toque directamente sus variables de respaldo.

Los desarrolladores de .NET pueden usar propiedades automáticas para hacer cumplir esto, ya que ni siquiera puede ver las variables de respaldo en el momento del diseño.

Mel
fuente
7

Depende. Es más una cuestión de estilo que cualquier otra cosa, y no hay una regla estricta.

Steve McLeod
fuente
7

Puedo estar equivocado porque soy autodidacta, pero NUNCA utilizo propiedades públicas en mis clases de Java, siempre son privadas o protegidas, por lo que el código externo debe acceder mediante getters / setters. Es mejor para fines de mantenimiento / modificación. Y para el código de la clase interna ... Si el método getter es trivial, uso la propiedad directamente, pero siempre uso los métodos setter porque podría agregar código fácilmente para disparar eventos si lo deseo.

Telcontar
fuente
7

Si no edito la propiedad, get_property()usaré un método público a menos que sea una ocasión especial, como un objeto MySQLi dentro de otro objeto, en cuyo caso haré pública la propiedad y me referiré a ella como $obj->object_property.

Dentro del objeto siempre es $ this-> propiedad para mí.

Ross
fuente
5

Bueno, parece que con la implementación predeterminada de las propiedades de C # 3.0, la decisión se toma por usted; TIENE que establecer la propiedad utilizando el establecedor de propiedades (posiblemente privado).

Personalmente, solo uso el miembro posterior privado cuando no hacerlo causaría que el objeto caiga en un estado menos que deseable, como cuando se inicializa o cuando se trata de almacenamiento en caché / carga diferida.

Moneda
fuente
5

Me gusta la respuesta de cmcculloh , pero parece que la más correcta es la de Greg Hurlman . Use getter / setter todo el tiempo si comenzó a usarlos desde el principio y / o está acostumbrado a trabajar con ellos.

Como acotación al margen, personalmente encuentro que usar getter / setter hace que el código sea más fácil de leer y depurar más adelante.

Robinho
fuente
4

Como se indica en algunos de los comentarios: a veces debería, a veces no. La gran parte de las variables privadas es que puedes ver todos los lugares en los que se utilizan cuando cambias algo. Si su getter / setter hace algo que necesita, utilícelo. Si no importa, tú decides.

Se podría hacer el caso opuesto de que si usa el getter / setter y alguien cambia el getter / setter, tienen que analizar todos los lugares donde el getter y el setter se usan internamente para ver si estropea algo.

svrist
fuente