¿Es esta forma de llamar a una función una mala práctica?

10

Tengo el siguiente código:

public void moveCameraTo(Location location){
    moveCameraTo(location.getLatitude(), location.getLongitude());
}

public void moveCameraTo(double latitude, double longitude){
    LatLng latLng = new LatLng(latitude, longitude);
    moveCameraTo(latLng);
}

public void moveCameraTo(LatLng latLng){
    GoogleMap googleMap =  getGoogleMap();
    cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, INITIAL_MAP_ZOOM_LEVEL);
    googleMap.moveCamera(cameraUpdate);
}

Creo que de esta manera elimino la responsabilidad de saber qué es un LatLngen otra clase, por ejemplo.

Y no necesita preparar los datos antes de llamar a la función.

¿Qué piensas?

¿Este enfoque tiene un nombre? ¿Es realmente una mala práctica?

Tlaloc-ES
fuente
2
Creo que solo se trata de encapsulación utilizando la sobrecarga de métodos incorporada en el lenguaje. No es bueno / malo. Solo una herramienta que puede ayudar o dañar su código.
bitsoflogic
55
Si su objetivo es ocultar LatLnga los clientes de esta Cameraclase, entonces probablemente no quiera moveCameraTo(LatLng)serlo public.
bitsoflogic
Además de los consejos dados en las respuestas, este se siente como un buen lugar para mencionar a YAGNI. No lo vas a necesitar. No defina métodos de API antes de que haya un buen caso de uso porque ... No lo va a necesitar.
Patrick Hughes
No hay nada malo con moveCameraToLocationy moveCameraTo/ moveCameraToCoords. Definitivamente no querría pasar Location / lat / long todos con los mismos nombres.
dentro del

Respuestas:

9

Está utilizando la función de sobrecarga de métodos de sus idiomas para ofrecer a la persona que llama formas alternativas de resolver la dependencia de los métodos de la información posicional. Luego está delegando a otro método para resolver el trabajo restante de actualización de la cámara.

El olor del código aquí sería si sigues extendiendo la cadena de métodos que llaman métodos. El método de toma de ubicación llama al método de toma doble que llama al método de toma de latLng que finalmente llama a algo que sabe cómo actualizar la cámara.

Las cadenas largas son tan fuertes como su eslabón más débil. Cada extensión de la cadena aumenta la huella de código que tiene que funcionar o esto se rompe.

Es un diseño mucho mejor si cada método toma el camino más corto posible para resolver el problema que se le ha presentado. Eso no significa que cada uno debe saber cómo actualizar la cámara. Cada uno debe traducir su tipo de parámetro de posición a un tipo uniforme que se pueda pasar a algo que sepa cómo actualizar la cámara cuando se presente este tipo.

Hazlo de esa manera y puedes eliminar uno sin romper la mitad de todo lo demás.

Considerar:

public void moveCameraTo(Location location){
    moveCameraTo( new LatLng(location) );
}

Esto hace que lidiar con el problema de la latitud y la longitud LatLng. El costo es que difunde el conocimiento de LatLngalrededor. Eso puede parecer costoso, pero en mi experiencia es una alternativa preferible a la obsesión primitiva, que es lo que evita establecer un objeto de parámetro .

Si Locationes refactorizable pero LatLngno lo es, considere resolver esto agregando una fábrica a Location:

moveCameraTo( location.ToLatLng() );

Esto también evita muy bien la obsesión primitiva.

naranja confitada
fuente
1
No me parece tan malo, en realidad es solo una conveniencia para el consumidor. Si esto se encadenara 10 veces o si el consumidor realmente no necesita todas estas opciones, lo llamaría un olor a código.
mcknz
1
Pero, ¿cuál es la alternativa de poner toda la lógica para transformar dobles en LagLng o Location to LagLng en cada función?
Tlaloc-ES
@ Tlaloc-ES mejor?
candied_orange
@ Tlaloc-ES La "transformación" solo tiene que suceder una vez cuando las primitivas se cargan en la lógica de dominio. Ocurriría cuando deserialice el DTO. Luego, toda su lógica de dominio puede pasar LatLngu Locationobjetos. Puede mostrar la relación entre los dos con New LatLng(Location)o Location.toLatLng()si necesita pasar de uno a otro.
bitsoflogic
1
@ Tlaloc-ES Lectura relacionada: Argumento de bandera por Martin Fowler. Lea la sección "Implementación enredada".
Marc.2377
8

No hay nada particularmente malo con su solución.

Pero mi preferencia personal sería que esos métodos no sean tan útiles. Y simplemente complique la interfaz de cualquier objeto del que formen parte.

El void moveCameraTo(double latitude, double longitude)realmente no simplifica el código, ya que no veo ningún problema simplemente llamando moveCameraTo(new LatLng(latitude, longitude));en su lugar. Este método también huele a obsesión primitiva.

El void moveCameraTo(Location location)podría resolverse mejor probando el Location.ToLatLng()método y llamando moveCameraTo(location.ToLatLng()).

si esto fuera C # y si tales métodos fueran realmente necesarios, los preferiría como métodos de extensión en lugar de métodos de instancia. El uso de métodos de extensión se volvería realmente obvio si intentara abstraer y probar esta instancia de forma unitaria. Como sería mucho más fácil simplemente falsificar un método único en lugar de múltiples sobrecargas con conversiones simples.

Creo que de esta manera elimino la responsabilidad de saber qué es un LatLng en otra clase, por ejemplo.

No veo ninguna razón por la que esto sea un problema. Siempre que su código haga referencia a la clase que contiene void moveCameraTo(LatLng latLng), aún depende indirectamente de ella LatLng. Incluso si esa clase nunca se instancia directamente.

Y no necesita preparar los datos antes de llamar a la función.

No entiendo lo que quieres decir. Si significa crear una nueva instancia o transformar clases de una a otra, no veo ningún problema con eso.

Pensando en ello, creo que lo que digo también es compatible con el diseño de API de .NET. Históricamente, muchas clases .NET siguieron su enfoque de tener muchas sobrecargas con diferentes parámetros y conversiones simples dentro. Pero eso fue antes de que existieran los métodos de extensión. Las clases .NET más modernas son más livianas en sus propias API y si hay algún método con sobrecarga de parámetros, se proporcionan como métodos de extensión. Un ejemplo más antiguo es NLog ILogger que tiene docenas de sobrecargas para escribir en el registro. Compare eso con las nuevas Microsoft.Extensions.Logging.ILogger que tiene un total de 3 métodos (y solo 1 si cuenta el registro en sí). Pero hay muchos ayudantes y varias parametrizaciones como métodos de extensión .

Creo que esta respuesta muestra que algunos idiomas tendrían herramientas para hacer un diseño como este más agradable. No conozco mucho Java, así que no estoy seguro de si habría algún equivalente. Pero incluso usar métodos estáticos simples podría ser una opción.

Eufórico
fuente
No estoy seguro de por qué, pero me encuentro apoyando esta respuesta a pesar de tener una competencia. Creo que lograste mejorar el punto. Mi único comentario sería recordar que no todos los que se ocupan de este problema están en .NET. +1
candied_orange
@candied_orange Derecha. Ahora que me veo mejor con la pregunta de OP, se parece más a Java que a C #.
Eufórico
Creo que realmente no tengo ningún problema en uso moveCameraTo(new LatLng(latitude, longitude));en ningún lugar del proyecto, pero creo que es más claro el uso directo de moveCametaTo (latLng), es como un archivo en Java, puede pasar la ruta como una cadena, o como una clase de ruta
Tlaloc-ES
1

No estoy seguro de cuál es el nombre correcto para esto, si tiene uno, pero es una buena práctica. Expone múltiples sobrecargas, lo que permite que la clase que llama determine qué conjunto de parámetros desea usar. Como usted dice, otra clase puede no saber qué es un LatLngobjeto, pero podría saberlo Location.

Hacer que un método llame al otro también es clave, ya que no desea código duplicado en esos métodos. Como lo ha hecho, elija un método para que sea el que haga el trabajo y haga que los otros métodos lo llamen (directa o indirectamente)

mmathis
fuente
1

Si te importa usar algún tipo de método, es solo una función de sobrecarga de métodos, es bueno.

Pero no se elimina la responsabilidad de saber qué es un LatLng . Porque te estás inicializando LatLng latLng = new LatLng(latitude, longitude). Esto es totalmente dependiente de LatLng. (Para comprender por qué la inicialización es un problema de dependencia, puede verificar la inyección de dependencia ) Crear un método sobrecargado solo ayuda a los clientes que no les importa LatLng. Si quiere decir esto, también es bueno, pero no creo que sea un enfoque. Son solo muchos métodos de servicio para clientes.

Entonces, hay dos opciones para diseñar su arquitectura:

  1. Cree muchos métodos sobrecargados y proporciónelos al cliente.
  2. Cree algunos métodos sobrecargados que necesiten parámetros como interfaz o clase concreta.

Me escapo lo más posible al crear métodos que necesitan tipos primitivos como parámetros (Opción 1). Porque si su negocio cambia muchas veces y necesita reproducir los parámetros del método, es realmente difícil cambiar e implementar todas las funciones de la persona que llama.

En lugar de esto, use interfaces (inyección de dependencia). Si cree que es costoso y lleva más tiempo, utilice las clases y proporcione sus métodos de extensión del asignador (Opción 2).

Engineert
fuente