¿Es malo crear clases cuyo único propósito sea convertir implícitamente a otra clase?


10

Imagine una situación en la que estamos usando una biblioteca que le permite crear Circleobjetos, donde puede especificar el radio y el centro del círculo para definirlo. Sin embargo, por alguna razón, también toma un flavourparámetro requerido . Ahora digamos que realmente necesito usar Circlemi propia aplicación, pero para los fines de mi aplicación puedo configurar el sabor para que sea Flavours.Cardboardcada vez.

Para "resolver" esto, creo mi propia Circleclase en un espacio de nombres diferente, que solo toma radiusy centercomo parámetros, pero tiene un convertidor implícito a la Circleclase de la biblioteca externa que simplemente crea un Circle(this.radius, this.center, Flavours.Cardboard)objeto. Entonces, donde sea que necesite el otro tipo de Circle, dejo que la conversión automática tenga lugar.

¿Cuáles son las consecuencias de crear tal clase? ¿Hay alguna solución mejor? ¿Habría alguna diferencia si mi aplicación fuera una API construida sobre esta biblioteca externa, destinada a ser utilizada por otros programadores?


Esto parece una variación del patrón de adaptador , aunque parece ser de dudoso valor aquí (es simplemente una conveniencia para evitar establecer un parámetro).
Robert Harvey

55
¿Por qué no crear una MakeCircle función ?
user253751

1
@immibis Thay fue mi primer pensamiento. Cuando estoy haciendo juegos, a menudo creo una función similar a la makePlayerque solo acepta las coordenadas para colocar al jugador, pero delega en un constructor mucho más complejo.
Carcigenicate

Respuestas:


13

Si bien no siempre es malo, es bastante raro que las conversiones implícitas sean su mejor opción.

Hay problemas

  1. Las conversiones implícitas no son muy legibles.
  2. Debido a que está haciendo un nuevo objeto, cualquier cambio en el objeto original no será visto por el que está convirtiendo, lo que provocará errores.
  3. Si está tirando el objeto, es basura extra para limpiar.
  4. Si hay un problema, sucederá cuando ocurra la conversión, no cuando se cree la cosa, haciendo que los errores sean más difíciles de rastrear.

En general, hay mejores soluciones.

  1. Haga su propio envoltorio delgado que use la otra clase / marco internamente.
  2. Cree un método auxiliar que tome los argumentos del constructor que desee y proporcione el que está arreglado, devolviendo el objeto real sin tener que especificar el argumento que no le interesa.
  3. Herede de la clase problemática y proporcione su propio constructor más agradable.
  4. Date cuenta de que pasar el argumento extra realmente no es tan importante.

Personalmente, considero que el n. ° 2 es el más sencillo de implementar y el menos gravoso en el diseño. Los demás pueden estar bien, dada la situación y qué más está tratando de hacer con estas clases.

La conversión implícita es un último recurso, y solo me parece que realmente vale la pena cuando tengo functores de estilo C ++ que estoy tratando de hacer: objetos de estrategia que convierto implícitamente en tipos de delegado.


1

Dado el escenario que está describiendo, puede pensar en esto en términos de aplicación de función parcial.

Un constructor es una función (al menos en teoría; en C #, puede crear una "función de fábrica" ​​que llama al constructor):

Func<double, Point, Flavour, Circle> MakeCircle = (r, p, f) => new Circle(r, p, f);

para aplicación parcial, lo siguiente será suficiente:

public static Func<T1, T2, R> Partial<T1, T2, T3, R>(this Func<T1, T2, T3, R> func, T3 t3)
   => (t1, t2) => func(t1, t2, t3);

Ahora puede obtener su constructor que solo requiere 2 parámetros:

Func<double, Point, Circle> MakeCardboardCircle = Circle.Partial(Flavours.Cardboard)

Entonces ahora tiene una función de fábrica con sus parámetros deseados

Circle c = MakeCardboardCircle(1.0, new Point(0, 0)))

Por cierto, esto es claramente equivalente a la opción 2 anterior, solo desde una perspectiva más funcional.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.