¿Hay algún inconveniente real en el encadenamiento de métodos autorreferenciales?

14

Hace poco sugerí que se implementara un método de encadenamiento para una cierta clase en un determinado proyecto para que la legibilidad del código pudiera mejorarse. Obtuve una "interfaz fluida que no debería implementarse solo por conveniencia, sino por respuesta semántica" y mi sugerencia fue rechazada. Respondí que no estaba sugiriendo una interfaz fluida sino un método que se encadena (ambos pueden confundirse entre sí, lea en la parte inferior) para mejorar la legibilidad y la comodidad de la codificación, la sugerencia fue rechazada nuevamente.

De todos modos, esto me hizo pensar que tal vez podría incurrir en una mala práctica al devolver siempre "esto" en métodos que se supone que no deben devolver nada (por ejemplo, los establecedores).

Mi pregunta es: ¿se puede considerar la aplicación de la convención anterior como una mala práctica o un abuso, por qué? No creo que haya inconvenientes en el rendimiento, ¿o sí?

    
pregunta dukeofgaming 30.05.2011 - 10:36

4 respuestas

9

No

Como señala Kent Beck , el código se lee con mucha más frecuencia de lo que está escrito.

Si el encadenamiento de métodos hace que su código sea más legible, entonces use el encadenamiento de métodos.

    
respondido por el Steven A. Lowe 30.05.2011 - 18:24
8

Sí, hay inconvenientes

El código que es fácil de leer es bueno, pero también tenga cuidado con lo que el código comunica también. Cuando los métodos de un objeto siempre devuelven el objeto, se comunica un par de cosas:

  1. Necesito una configuración avanzada que no sea necesariamente obvia en el orden en que se deben configurar o configurar las cosas
  2. Cada llamada de método posterior se basa en la última

Caso de uso válido: consultas de base de datos ad hoc

Las bibliotecas de clases existen en la mayoría de los idiomas que le permiten consultar una base de datos sin tener que recurrir a SQL codificado. Tome el Entity Framework para .NET como ejemplo:

DBContext db = new DBContext();
List<Post> posts = db.Posts
    .Where(post => post.Title.Contains("Test"))
    .OrderBy(post => post.DateCreated)
    .ToList();

Esta es una interfaz fluida donde cada llamada de método subsiguiente se basa en la anterior. Leer estas llamadas lógicamente tiene sentido en el contexto de consultar una base de datos.

Caso de uso no válido: azúcar sintáctica para configurar propiedades

Ahora vamos a usar el mismo patrón con la clase Post :

public class Post
{
    public string Title { get; set; }
    public DateTime DateCreated { get; set; }
    public string Body { get; set; }

    public Post SetTitle(string title)
    {
        Title = title;

        return this;
    }

    public Post SetDateCreated(DateTime created)
    {
        DateCreated = created;

        return this;
    }

    public Post SetBody(string body)
    {
        Body = body;

        return this;
    }
}

Ahora veamos cómo usarías esta clase:

Post post = new Post()
    .SetTitle("Test")
    .SetDateCreated(DateTime.Now)
    .SetBody("Just a test");

Cuando veo este código, inmediatamente hago esta pregunta: "Después de llamar a SetBody , ¿consulta la base de datos? ¿Debo llamar a otro método para decir 'Ya he terminado'"

¿A qué llama el método encadenado se comunican al código mediante la clase Post ?

  1. Tengo una configuración complicada
  2. Cada llamada de método se basa en la anterior

¿Es esto en realidad verdadero? No. La clase Post no tiene una configuración complicada. Al establecer el título, la fecha de creación y el cuerpo, no se construyen entre sí hacia un objetivo final más complicado. Has triturado una clavija cuadrada en un agujero redondo.

El inconveniente del encadenamiento de métodos autorreferenciales es que usted comunica que se requieren varias llamadas de métodos para hacer algo, y que cada llamada se basa en la última. Si esto no es cierto, entonces el encadenamiento de métodos podría estar comunicando algo incorrecto a otros programadores.

Cuando sus compañeros de trabajo dijeron:

  

Las interfaces fluidas no deben implementarse solo por conveniencia, sino por semántica

Fueron absolutamente correctos. Una interfaz fluida, o método de encadenamiento, comunica algo en sí mismo que podría no ser cierto.

    
respondido por el Greg Burghardt 16.12.2014 - 14:53
1

El principal inconveniente es una pérdida de claridad. Por ejemplo:

x.foo();
x.bar();
x.baz();

Dado que ninguna de esas declaraciones devuelve un valor (o si lo hacen, se ha ignorado), solo pueden ser útiles si producen efectos secundarios. Contraste eso a:

x.foo()
 .bar()
 .baz();

Primero, no está claro que bar y baz operen en objetos del mismo tipo que x , a menos que sepa a ciencia cierta que la clase de x es la única clase con esos métodos. Incluso si ese es el caso, no está claro que los métodos operen en x , u objetos nuevos.

Resaltar las partes del código que tienen efectos secundarios es útil, ya que necesita rastrear esos efectos secundarios para razonar sobre el programa. Debe sopesar la pérdida potencial de claridad frente a la ganancia potencial en la facilidad de escritura del código, pero también debe considerar que el código se lee más de lo que se escribe.

    
respondido por el Doval 16.12.2014 - 17:53
0

Considere todos los elementos estilísticos de los lenguajes de programación (a diferencia del lenguaje de máquina de codificación manual), y debilita el argumento de "semántica no conveniencia".

Mucho de lo que hacemos como ingenieros es proporcionar comodidad en torno a la semántica.

    
respondido por el Rob 16.12.2014 - 17:32

Lea otras preguntas en las etiquetas