No creo que haya una respuesta agnóstica del idioma a esto, ya que lo que constituye una "propiedad" es una pregunta específica del idioma, y lo que espera una persona que llama de una "propiedad" también es una pregunta específica del idioma. Creo que la forma más fructífera de pensar en esto es pensar en cómo se ve desde el punto de vista de la persona que llama.
En C #, las propiedades se distinguen porque están capitalizadas (convencionalmente) (como los métodos) pero carecen de paréntesis (como las variables de instancia pública). Si ve el siguiente código, sin documentación, ¿qué espera?
var reciprocalHeading = myHeading.Reciprocal;
Como un novato relativo de C #, pero uno que ha leído las Directrices de uso de propiedades de Microsoft , esperaría Reciprocal
, entre otras cosas:
- ser un miembro de datos lógico de la
Heading
clase
- ser económico para llamar, de modo que no sea necesario que guarde en caché el valor
- falta de efectos secundarios observables
- producir el mismo resultado si se llama dos veces seguidas
- (tal vez) ofrecer un
ReciprocalChanged
evento
De estos supuestos, (3) y (4) son probablemente correctos (suponiendo que Heading
es un tipo de valor inmutable, como en la respuesta de Ewan ), (1) es discutible, (2) es desconocido pero también discutible, y (5) es poco probable que tiene sentido semántico (aunque cualquier cosa que tenga un encabezado quizás debería tener un HeadingChanged
evento). Esto me sugiere que en una API de C #, "obtener o calcular el recíproco" no debe implementarse como una propiedad, pero especialmente si el cálculo es barato e Heading
inmutable, es un caso límite.
(Sin embargo, tenga en cuenta que ninguna de estas preocupaciones tiene nada que ver con si llamar a la propiedad crea una nueva instancia , ni siquiera (2). Crear objetos en el CLR, en sí mismo, es bastante barato).
En Java, las propiedades son una convención de nomenclatura de métodos. Si yo veo
Heading reciprocalHeading = myHeading.getReciprocal();
mis expectativas son similares a las anteriores (si se establecen de manera menos explícita): espero que la llamada sea barata, idempotente y carente de efectos secundarios. Sin embargo, fuera del marco de JavaBeans, el concepto de una "propiedad" no es tan significativo en Java, y particularmente cuando se considera una propiedad inmutable sin correspondencia setReciprocal()
, la getXXX()
convención está algo anticuada. Desde Effective Java , segunda edición (ya tiene más de ocho años):
Los métodos que devuelven una no boolean
función o atributo del objeto en el que se invocan generalmente se nombran con un sustantivo, una frase nominal o una frase verbal que comience con el verbo get
…. Hay un contingente vocal que afirma que solo la tercera forma (comenzando con get
) es aceptable, pero hay poca base para esta afirmación. Las dos primeras formas generalmente conducen a un código más legible ... (p. 239)
En una API contemporánea y más fluida, entonces, esperaría ver
Heading reciprocalHeading = myHeading.reciprocal();
- lo que nuevamente sugeriría que la llamada es barata, idempotente y carece de efectos secundarios, pero no diría nada sobre si se realiza un nuevo cálculo o si se crea un nuevo objeto. Esto esta bien; en una buena API, no me debería importar.
En Ruby, no existe tal cosa como una propiedad. Hay "atributos", pero si veo
reciprocalHeading = my_heading.reciprocal
No tengo forma inmediata de saber si estoy accediendo a una variable de instancia a @reciprocal
través de un attr_reader
método simple o de acceso, o si estoy llamando a un método que realiza un cálculo costoso. Sin embargo, el hecho de que el nombre del método sea un nombre simple calcReciprocal
sugiere, una vez más, que la llamada es al menos barata y probablemente no tiene efectos secundarios.
En Scala, la convención de nomenclatura es que los métodos con efectos secundarios toman paréntesis y los métodos sin ellos no, pero
val reciprocal = heading.reciprocal
podría ser cualquiera de:
// immutable public value initialized at creation time
val reciprocal: Heading = …
// immutable public value initialized on first use
lazy val reciprocal: Heading = …
// public method, probably recalculating on each invocation
def reciprocal: Heading = …
// as above, with parentheses that, by convention, the caller
// should only omit if they know the method has no side effects
def reciprocal(): Heading = …
(Tenga en cuenta que Scala permite varias cosas que, sin embargo, no se recomiendan en la guía de estilo . Esta es una de mis principales molestias con Scala).
La falta de paréntesis me dice que la llamada no tiene efectos secundarios; el nombre, nuevamente, sugiere que la llamada debería ser relativamente barata. Más allá de eso, no me importa cómo me da el valor.
En resumen: conozca el lenguaje que está utilizando y sepa qué expectativas traerán otros programadores a su API. Todo lo demás es un detalle de implementación.
Heading
un tipo inmutable yreciprocal
devolver una nuevaHeading
es una buena práctica de "pozo de éxito". (con la advertencia de que las dos llamadasreciprocal
deben devolver "lo mismo", es decir, deben pasar la prueba de igualdad).