¿Cuál es el punto de las propiedades?

11

Aquí hay algunos argumentos para las propiedades y mis contraargumentos:

Más fácil de usar que escribir métodos getter y setter

Los pares de métodos getter y setter son un olor a código. Hacer que sea más fácil escribir esto es como hacer que sea más fácil reprobar una prueba de matemáticas usando un formulario Scantron y completando todas las 'C'. Los objetos que contienen solo estado, para persistencia, no deberían usar getters / setters y deberían crear objetos inmutables en el momento de la persistencia.

Lo que es importante para un consumidor de un objeto es lo que hace, no cómo lo hace. Su comportamiento es lo que hace; su estado es como lo hace. Si te preocupa el estado de un objeto (excepto por la persistencia, aunque esto también rompe OO), simplemente no estás haciendo POO y perdiendo sus ventajas.

Dan una indicación aproximada del rendimiento a los consumidores.

Esto es algo que podría cambiar en el futuro, para cualquier propiedad dada. Supongamos que en la versión 1.0, acceder a PropertyX simplemente devuelve un campo. En la versión 1.5, si el campo es nulo, PropertyX usa el patrón de objeto nulo para crear un nuevo objeto nulo. En la versión 2.0, el campo se está validando aún más por el método getter en PropertyX.

A medida que la propiedad se vuelve más y más compleja, la indicación de rendimiento del uso de una propiedad parece cada vez menos veraz.

Son mejores que los campos públicos

Esto es verdad. Pero también lo son los métodos.

Representan un aspecto fundamentalmente diferente de un objeto que un método, y todos los consumidores del objeto deberían preocuparse por esto.

¿Estás seguro de que las dos afirmaciones anteriores son ciertas?

Son más fáciles de escribir, hombre

Claro, escribir myObject.Lengthes más fácil que escribir myObject.Length(), pero ¿no podría solucionarse con un poco de azúcar sintáctica?


¿Por qué usar métodos en lugar de propiedades?

  • Sin garantías de rendimiento. La API seguirá siendo veraz incluso si el método se vuelve más complejo. El consumidor deberá perfilar su código si se encuentra con problemas de rendimiento y no depender de la palabra de API.

  • Menos para que el consumidor piense. ¿Esta propiedad tiene un setter? Un método seguro no lo hace.

  • El consumidor está pensando desde una mentalidad OOP adecuada. Como consumidor de una API, estoy interesado en interactuar con el comportamiento de un objeto. Cuando veo propiedades en la API, se parece mucho al estado. De hecho, si las propiedades hacen demasiado, ni siquiera deberían ser propiedades, por lo que, en realidad, las propiedades en un estado API SON tal como aparecen para los consumidores.

  • El programador de la API pensará más profundamente sobre los métodos con valores de retorno, y evitará modificar el estado del objeto en dichos métodos, si es posible. La separación de los comandos de las consultas debe aplicarse siempre que sea posible.


Entonces te pregunto, ¿por qué usar propiedades en lugar de métodos? La mayoría de los puntos en MSDN son olores de código en sí mismos y no pertenecen ni a propiedades ni a métodos.

(Estos pensamientos me vinieron después de pensar en CQS).

xofz
fuente
55
+1. Las propiedades son métodos con la sintaxis de los campos y eso simplemente no tiene sentido.
Nemanja Trifunovic
23
@Nemanja Trifunovic: Tiene mucho sentido si has escrito type GetFoo() void SetFoo()diez mil veces. En todo mi tiempo escribiendo código C #, nunca me ha confundido una propiedad.
Ed S.
23
Me parece que ya te has decidido. ¿Cuál es la pregunta?
Dean Harding
99
@Nemanja Trifunovic: "Los captadores y los colocadores son generalmente malos" Puedes repetir eso tantas veces como quieras, pero no lo hará realidad. ¿Qué tal explicar por qué crees que son malos? En la medida en que SO se bloquea debido a escribir el nombre de la propiedad en lugar del nombre de la variable subyacente, es un error imposible de perder, ya que bloqueará su programa tan pronto como llame a la propiedad y es bastante raro. Cuando sucede, sé exactamente lo que hice para causarlo y lo arreglo en dos segundos. No veo el problema.
Ed S.
3
Simplemente pasar para señalar a @NemanjaTrifunovic que ese artículo sobre por qué los métodos getter y setter son malvados es bastante antiguo , se trata de Java y subraya una debilidad de Java : la debilidad de no tener propiedades . (por lo tanto, muestra demasiados detalles de implementación) ... mordiendo nuestra cola aquí. (debería titularse getters y setters son malos en Java, porque no tenemos un estándar bien pensado sobre ellos )
ZJR

Respuestas:

44

¿Por qué son "métodos contra propiedades"? Un método hace algo. Una propiedad es, bueno, un miembro de un objeto. Son cosas totalmente diferentes, aunque dos tipos de métodos comúnmente escritos, getters y setters, corresponden a propiedades. Dado que comparar propiedades con métodos en general no tiene sentido, supondré que querías hablar sobre getters / setters.

Los pares de métodos getter y setter son un olor a código.

No necesariamente, argumentaría, pero de cualquier manera esto no es una cuestión de captadores / establecedores versus propiedades, sino una cuestión de si cualquiera debe usarse. También tenga en cuenta que puede, por ejemplo, omitir la setXparte al igual que puede hacer propiedades de solo lectura.

Lo que es importante para un consumidor de un objeto es lo que hace, no cómo lo hace. Su comportamiento es lo que hace; su estado es como lo hace. Si te preocupa el estado de un objeto (excepto por la persistencia, aunque esto también rompe OO), simplemente no estás haciendo POO y perdiendo sus ventajas.

Una actitud muy cuestionable. Si la GUI desea generar datos almacenados por a DataStuffManagerImpl, necesita obtener ese número de alguna manera (y no, meter la mitad de la aplicación en la clase de widget no es una opción).

A medida que la propiedad se vuelve más y más compleja, la indicación de rendimiento del uso de una propiedad parece cada vez menos veraz.

[Los métodos tienen] No hay garantías de rendimiento. La API seguirá siendo veraz incluso si el método se vuelve más complejo. El consumidor deberá perfilar su código si se encuentra con problemas de rendimiento y no depender de la palabra de API.

En casi todos los casos, toda la lógica de validación, etc., sigue siendo efectivamente O (1), o de otro modo despreciable en costo. Si no, tal vez has ido demasiado lejos y es hora de un cambio. ¡Y un getX()método generalmente también se trata como barato!

Claro, escribir myObject.Length es más fácil que escribir myObject.Length (), pero ¿no podría solucionarse con un poco de azúcar sintáctica?

Las propiedades son ese azúcar sintáctico.

Menos para que el consumidor piense. ¿Esta propiedad tiene un setter? Un método seguro no lo hace.

"¿Hay un setter para este getter?" La misma diferencia.

El programador de la API pensará más profundamente sobre los métodos con valores de retorno, y evitará modificar el estado del objeto en dichos métodos, si es posible. La separación de los comandos de las consultas debe aplicarse siempre que sea posible.

No estoy seguro de lo que estás tratando de decirnos aquí. Para las propiedades, hay una ley no escrita aún más fuerte que no causa efectos secundarios.

ChrisF
fuente
3
+1, y no es una ley no escrita. Las pautas de uso de la propiedad en MSDN lo tienen escrito con muchos otros. Creo que OP debería analizarlos para aclararse muchas dudas. Y no puedo publicar un enlace aquí ya que estoy escribiendo esto desde mi teléfono, pero las pautas deberían ser fáciles de encontrar.
Decyclone
@delnan: Las propiedades no son ese azúcar sintáctico. Las propiedades se pueden tratar como campos (se pueden usar como destino de asignación, si tienen un establecedor). Los métodos no pueden.
xofz
1
@SamPearson: obj.x = ymapas obj.setX(y)y obj.xmapas a obj.getX(). ¿Cómo es eso diferente?
1
@SamPearson puede cambiar la visibilidad de un establecedor de propiedades y un getter independientes entre sí. Lo uso todo el tiempo con mis objetos de Entity Framework: mis setters están protegidos (por lo que solo el framework puede establecer un valor). Entonces es perfectamente viable decir int length = myObject.Length sin permitir myObject.Length = 10
Michael Brown
19

Los pares de métodos getter y setter son un olor a código.

Esa es una suposición defectuosa y completamente incorrecta. Los métodos Get / Set son una forma de encapsular un miembro de datos y de ninguna manera son un "olor a código". Realmente odio la forma en que algunas personas lanzan el término "olor a código", pero de todos modos ...

Esto es algo que podría cambiar en el futuro, para cualquier propiedad dada. Supongamos que en la versión 1.0, acceder a PropertyX simplemente devuelve un campo. En la versión 1.5, si el campo es nulo, PropertyX usa el patrón de objeto nulo para crear un nuevo objeto nulo. En la versión 2.0, el campo se está validando aún más por el método getter en PropertyX.

A medida que la propiedad se vuelve más y más compleja, la indicación de rendimiento del uso de una propiedad parece cada vez menos veraz.

Suena como una API mal diseñada, no veo cómo eso es culpa de la sintaxis de propiedad.

Las propiedades en C # eran simplemente azúcar sintáctica para un patrón muy común que hizo que nuestras vidas como programadores fueran un poco más fáciles. Sin embargo, en estos días, si desea usar el enlace de datos, debe "usar" propiedades, por lo que ahora son un poco más que el azúcar sintáctico. Supongo que realmente no estoy de acuerdo con ninguno de tus puntos y no entiendo por qué no te gusta una función de lenguaje que admite directamente un patrón común.

Ed S.
fuente
1
Voy a dar una recompensa para encontrar un término mejor que el código de olor. Simplemente lea un libro sobre refactorización donde se usa aproximadamente mil veces. Es como las uñas en una pizarra.
JeffO
1
@Jeff O: Sí, creo que las personas que parecen darle más vueltas a ese término generalmente no tienen mucha experiencia.
Ed S.
66
@Jeff O y @Ed S: IME, "código de olor" se ha convertido en el término habitual que las personas usan cuando realmente quieren decir "No me gusta, pero en realidad no tengo una razón"
Steven Evers
3
@SnOrfus: Sí, o cuando sostienen puntos de vista "religiosos" que a menudo tienen poco sentido en la práctica, como "un método nunca debe tener más de X número de líneas" , que a su vez suele ser solo una repetición de algo que leen en alguna parte.
Ed S.
1
El uso inapropiado de los métodos getter / setter es un olor a código, pero también debería ser el uso inapropiado de cualquier cosa . Incluso cuando las cosas tienen casos de uso estrechos, emplear tales cosas para esos casos de uso no debe considerarse un olor a código. La creación de setters para todo no debería ser un hábito ciego, pero uno no debería tener miedo de incluirlos cuando sea apropiado. Lo que es necesario es equilibrar la utilidad para los clientes de poder cambiar el estado, en lugar de poder descubrir en el futuro qué era el estado antes (fácil si el estado es inmutable). Ambos son útiles, pero el código debe elegir uno.
supercat
10

Tu premisa está mal.

Las propiedades no son en modo alguno un contrato de desempeño o implementación interna o lo que sea.
Las propiedades son pares de métodos especiales, que representan semánticamente un atributo, si lo desea. Y, por lo tanto, el único contrato es que una propiedad se comporte como cabría esperar que se comportara un atributo.
Si solicito el color de un objeto, no supongo que se obtiene mediante un acceso de campo simple o si se calcula justo a tiempo.
El punto principal es tener la capacidad de exponer el comportamiento de un atributo mediante el uso de métodos, mientras que es transparente para el consumidor de la interfaz, ya sea que esté utilizando un campo o accesores.

Tener atributos (y en realidad ocultar su implementación, ya que las propiedades se oponen a los campos) es una característica declarativa poderosa , que es la base para tener inspectores de objetos visuales y otra generación de vista automática, para el enlace de datos y muchas otras cosas útiles. Y lo más importante, también transporta claramente esta información para sus compañeros programadores.

back2dos
fuente
6

El consumidor está pensando desde una mentalidad OOP adecuada. Como consumidor de una API, estoy interesado en interactuar con el comportamiento de un objeto. Cuando veo propiedades en la API, se parece mucho al estado. De hecho, si las propiedades hacen demasiado, ni siquiera deberían ser propiedades, por lo que, en realidad, las propiedades en un estado API SON tal como aparecen para los consumidores.

Se supone que una propiedad es un estado. Si el setter subyacente o el código getter cambian para agregar significativamente al procesamiento requerido para establecer u obtener el estado, entonces realmente ya no es una propiedad y debe reemplazarlo con métodos. Esto depende de usted como desarrollador del código.

Poner demasiado código (cuánto depende demasiado) en un setter o getter está mal, pero solo porque sea posible no es una razón para descartar el patrón en todos los casos.

ChrisF
fuente
6

Una cosa que falta, y no sé si esto se debe a la ignorancia o si está pasando por alto este detalle intencionalmente, es que las propiedades SON métodos.

Cuando usa la sintaxis de propiedad de C #, el compilador crea silenciosamente métodos getter y setter con metadatos que le dicen a los lenguajes que entienden las propiedades como una característica sintáctica de primera clase para tratarlas como tales. Ese es, de hecho, el azúcar sintáctico que estás pidiendo. Algunos idiomas que se pueden ejecutar en el CLR no le ocultan completamente este detalle (Boo, si la memoria me sirve y algunas implementaciones de Lisp), y puede llamar a los captadores y establecedores explícitamente.

Las propiedades ocasionalmente tienen efectos secundarios, como desencadenar eventos de notificación de cambio (INotifyPropertyChanged, por ejemplo) o marcar una instancia de una clase como sucia. Aquí es donde tienen su valor real, aunque crearlos es un poco más de trabajo (excepto en Boo, que tiene macros con conocimientos de sintaxis).

Ahora, la pregunta más amplia es si los métodos getter y setter son, de hecho, una buena cosa. Claramente hay compensaciones; Si tiene métodos de mutadores, su código es inherentemente menos paralelo, porque ahora tiene que lidiar con problemas de sincronización de hilos. Y es muy posible que corras el riesgo de violar la Ley de Demeter usando métodos mutadores (ya sea llamados propiedades o métodos getter / setter; son equivalentes), porque es muy conveniente hacerlo.

Pero a veces es lo correcto. A veces, su problema es tomar datos de alguna fuente, cambiarlos un poco, presentar los datos actualizados al usuario y guardar los cambios. Ese idioma está bien servido por las propiedades. Como dice el artículo de Allen Holub , solo porque los captadores y los colocadores tienen problemas no significa que nunca debas usarlos. (Loro abstracto Guruspeak considerado dañino). Incluso cuando sigue el enfoque de Clase / Responsabilidades / Colaboradores, aún termina exponiendo información o presentaciones de información a alguien; el punto es minimizar el área de la superficie del enredo.

La ventaja de las propiedades es que es muy fácil que otro objeto se aproveche de ellas. La desventaja de las propiedades es que es muy fácil que otro objeto se aproveche de ellas, y no puede evitarlo fácilmente.

La mutación de objetos tiene sentido en la capa del controlador, por ejemplo, en una arquitectura MVC. Ese es tu colaborador. Su punto de vista también es un colaborador, pero no debería estar mutando directamente sus objetos, porque tiene diferentes responsabilidades. Introducir código de presentación en los objetos de su negocio tampoco es necesariamente la forma correcta de evitar captadores / establecedores.

La ecuación cambia un poco si usa abstracciones funcionales, en lugar de pura OO, lo que generalmente hace que hacer copias de un objeto "registro" con un par de cambios sea bastante trivial, aunque no gratuito. Y oye, si estás tratando de obtener garantías de rendimiento, las propiedades son generalmente más predecibles que la reconstrucción diferida de una colección inmutable.

JasonTrue
fuente
5

Otra razón importante en mi libro para usar propiedades es que pueden aumentar considerablemente la legibilidad.

account.setBalance(Account.getBalance()+deposit);

es claramente mucho menos legible que

account.Balance += deposit;
apoorv020
fuente
66
Excepto que el saldo no debe ser una propiedad porque seguramente habrá una lógica comercial significativa asociada con el cambio (verificar el sobregiro; cobrar el cargo por servicio; registrar la transacción, etc.) Su punto de legibilidad es completamente válido si se aplica a un ejemplo diferente ( Temperatura, color de fondo, etc.)
Kate Gregory
99
¿Por qué no account.Deposit (cantidad)?
xofz
44
@Sam Pearson: +1. Un ejemplo perfecto de por qué los captadores / setters a menudo indican un diseño deficiente.
Nemanja Trifunovic
4

Tienes casi el punto de vista religioso opuesto para mí :)

Cuando me mudé de Delphi a Java, la falta de propiedades fue una gran afrenta para mí. Estaba acostumbrado a declarar una propiedad y señalarla directamente a una variable privada o escribir un getter y setter (protegido) y luego "conectarlos" a la propiedad. Esto encapsulaba la propiedad y controlaba cómo debería accederse de una manera clara e inequívoca. Puede tener una propiedad de solo lectura que calcule el total cuando se accede y lo llame "Total", no "_getTotal ()" o globos similares. También significaba que podía restringir el acceso a las propiedades protegiéndolas en la clase base abstracta y luego moviéndolas a público o publicadas en subclases.

Para mí, las propiedades son una forma más natural y expresiva de establecer y obtener el estado del objeto. Confiar en convenciones de codificación no forzadas es más un "olor a código" que cualquier cosa por la que critiques las propiedades. Además, como han dicho otros, idear un uso de propiedades mal diseñado y usar sus fallas para tratar de descartar el concepto de propiedades en general es una forma extremadamente mala. Es posible que solo haya visto un mal uso de las propiedades y suponga que es así, supongo, pero debería investigar más antes de volverse demasiado dogmático.

mcottle
fuente
+1 Que de hecho es un uso real de una propiedad. Gran respuesta. " También significaba que se podía restringir el acceso a las propiedades al protegerlas en la clase base abstracta y luego moverlas al público o publicarlas en subclases " .
Karthik Sreenivasan
Delphi hace un mal uso de las propiedades hasta la náusea. No ordena la lista, establece su sorted propiedad en true. Así que configurarlo te falseda la lista original. : D ¿O lo baraja al azar? : D O lo que sea, es estúpido. Además, es muy lento en comparación con un conjunto ordenado adecuado. Las propiedades no son malas, pero he aprendido a usarlas con moderación (hasta el punto de estar bastante contento con getter y setters; estoy usando principalmente Java).
maaartinus
1

Una de las razones por las que las propiedades se introdujeron en Java Beans Framework fue para permitir la integración con un IDE: puede arrastrar esos componentes al IDE y editar las propiedades utilizando editores de propiedades.

(en aquel entonces eran solo captadores y colocadores regulares, y se definieron solo por la convención de nomenclatura, y esto realmente olía)

Hoy en día, hay incluso más casos en los que se accede a las propiedades y se modifican no a través del código regular, como durante la depuración.

Ophir Yoktan
fuente
1

Otro ángulo: realmente vinieron de VB. Recuerde, en los días oscuros del siglo XX, cuando se concibió .NET, el énfasis principal era que era un reemplazo fácil y directo para VB para que sus programadores de VB pudieran arrastrar y soltar cosas en los formularios web. VB tenía propiedades, por lo que necesitaba mantener esa característica para que las cosas se tradujeran correctamente.

Wyatt Barnett
fuente
1
Anders Heljsberg diseñó C # (y algo de IL) y también diseñó Delphi, que tenía propiedades.
Jesse C. Slicer
1

Hay al menos dos propósitos para las propiedades:

  • Son conceptualmente idénticos a los campos, incluso si se implementan de manera diferente. Un captador no debe cambiar el estado del objeto y no debe tener efectos secundarios. Un setter solo debe cambiar el estado de maneras conceptualmente similares a modificar un campo y no tener otros efectos secundarios.

  • Son sintácticamente idénticos a los campos públicos (posiblemente de solo lectura). Esto significa que un campo público se puede cambiar a una propiedad sin interrumpir las llamadas en el nivel de origen.

dsimcha
fuente
Sí, pero tenga en cuenta la palabra "debería". No hay nada en las propiedades que evite que los captadores tengan efectos secundarios y, de hecho, he visto numerosos casos en los que ese fue el caso.
Nemanja Trifunovic
1
Cambio de un campo público a una propiedad va a romper la compatibilidad binaria, el código de consumir tendrá que volver a compilar - aunque no modificados, que supongo que es lo que estaban haciendo en :)
MattDavey
@ MattDavey: Gracias. Eso es a lo que me refiero. Editado
dsimcha