No sé por qué, pero siempre siento que estoy "haciendo trampa" cuando uso la reflexión, tal vez es por el éxito en el rendimiento que sé que estoy tomando.
Una parte de mí dice que si es parte del lenguaje que está usando y puede lograr lo que está tratando de hacer, entonces, ¿por qué no usarlo? La otra parte de mí dice que tiene que haber una manera de hacerlo sin usar la reflexión. Supongo que tal vez depende de la situación.
¿Cuáles son los posibles problemas que debo tener en cuenta al usar la reflexión y qué tan preocupado debería estar por ellos? ¿Cuánto esfuerzo vale la pena gastar para tratar de encontrar una solución más convencional?
Respuestas:
No, no es trampa: es una forma de resolver problemas en algunos lenguajes de programación.
Ahora, a menudo no es la mejor solución (más limpia, más simple, más fácil de mantener). Si hay una mejor manera, use esa de hecho. Sin embargo, a veces no lo hay. O si lo hay, es mucho más complejo, implica una gran cantidad de duplicación de código, etc., lo que lo hace inviable (difícil de mantener a largo plazo).
Dos ejemplos de nuestro proyecto actual (Java):
fieldX
con el campo apropiado en la clase y para inicializar el último. En algunos casos, puede crear un cuadro de diálogo GUI simple a partir de las propiedades identificadas sobre la marcha. Sin reflexionar, esto tomaría cientos de líneas de código en varias aplicaciones. Así que la reflexión nos ayudó a armar una herramienta simple rápidamente, sin mucho alboroto, y nos permitió centrarnos en la parte importante (pruebas de regresión de nuestra aplicación web, análisis de registros del servidor, etc.) en lugar de lo irrelevante.La conclusión es, como cualquier herramienta poderosa, la reflexión también se puede utilizar para dispararse en el pie. Si aprende cuándo y cómo (no) usarlo, puede brindarle soluciones elegantes y limpias para problemas difíciles. Si abusa de él, puede convertir un problema simple en un desastre complejo y feo.
fuente
if (propName = n) setN(propValue);
, puede nombrar sus (es decir) etiquetas XML de la misma manera que sus propiedades de código y ejecutar un ciclo sobre ellas. Este método también hace que sea mucho más simple agregar propiedades más adelante.No es trampa. Pero generalmente es una mala idea en el código de producción al menos por las siguientes razones:
Sugeriría limitar el uso de la reflexión a los siguientes casos:
En todos los demás casos, sugeriría encontrar un enfoque que evite la reflexión. Definir una interfaz con el (los) método (s) apropiado (s) e implementarlo en el conjunto de clases a las que desea llamar el (los) método (s) suele ser suficiente para resolver la mayoría de los casos simples.
fuente
La reflexión es solo otra forma de metaprogramación, y tan válida como los parámetros basados en tipos que se ven en la mayoría de los idiomas en estos días. La reflexión es poderosa y genérica, y los programas reflexivos son de alto orden de mantenibilidad (cuando se usan correctamente, por supuesto) y más que los programas puramente orientados a objetos o procedimientos. Sí, pagas un precio de rendimiento, pero con gusto elegiría un programa más lento que sea más fácil de mantener en muchos, o incluso en la mayoría de los casos.
fuente
Seguramente todo depende de lo que intentes lograr.
Por ejemplo, escribí una aplicación de verificación de medios que utiliza la inyección de dependencia para determinar qué tipo de medios (archivos MP3 o JPEG) verificar. El shell necesitaba mostrar una cuadrícula que contenía la información pertinente para cada tipo, pero no tenía conocimiento de lo que iba a mostrar. Esto se define en el ensamblado que lee ese tipo de medios.
Por lo tanto, tuve que usar la reflexión para obtener el número de columnas para mostrar y sus tipos y nombres para poder configurar la cuadrícula correctamente. También significaba que podía actualizar la biblioteca inyectada (o crear una nueva) sin cambiar ningún otro código o archivo de configuración.
La única otra forma habría sido tener un archivo de configuración que debería actualizarse cuando cambié el tipo de medio que se verifica. Esto habría introducido otro punto de falla para la aplicación.
fuente
Reflection es una herramienta increíble si eres autor de una biblioteca y, por lo tanto, no tienes influencia sobre los datos entrantes. Una combinación de reflexión y metaprogramación puede permitir que su biblioteca funcione a la perfección con llamadores arbitrarios, sin que tengan que saltar a través de aros de generación de código, etc.
Sin embargo, intento disuadir de la reflexión en el código de la aplicación ; en la capa de la aplicación deberías usar diferentes metáforas: interfaces, abstracción, encapsulación, etc.
fuente
La reflexión es fantástica para crear herramientas para desarrolladores.
Como permite que su entorno de compilación inspeccione el código y genere potencialmente las herramientas correctas para manipular / iniciar la inspección del código.
Como técnica de programación general, puede ser útil, pero es más frágil de lo que la mayoría de la gente imagina.
Un uso realmente desarrollado para la reflexión (IMO) es que hace que escribir una biblioteca genérica de transmisión sea muy simple (siempre y cuando la descripción de su clase nunca cambie (entonces se convierte en una solución muy frágil)).
fuente
El uso de la reflexión a menudo es perjudicial en los idiomas OO si no se usa con gran conocimiento.
He perdido la cuenta de cuántas preguntas malas he visto en los sitios de StackExchange donde
Aquí hay ejemplos típicos.
La mayor parte del punto de OO es que
Si en algún punto de su código, el punto 2 no es válido para un objeto que le ha pasado, entonces uno o más de estos es verdadero
Los desarrolladores poco calificados simplemente no entienden esto y creen que se les puede pasar cualquier cosa en cualquier parte de su código y hacer lo que quieran de un conjunto de posibilidades (codificadas). Estos idiotas usan mucho la reflexión .
Para los lenguajes OO, la reflexión solo debería ser necesaria en la metaactividad (cargadores de clases, inyección de dependencias, etc.). En esos contextos, la reflexión es necesaria porque está proporcionando un servicio genérico para ayudar a la manipulación / configuración del código del cual no sabe nada por una razón buena y legítima. En casi cualquier otra situación, si está buscando la reflexión, entonces está haciendo algo mal y debe preguntarse por qué este código no sabe lo suficiente sobre el objeto que se le ha pasado.
fuente
Una alternativa, en los casos en que el dominio de las clases reflejadas está bien definido, es usar la reflexión junto con otros metadatos para generar código , en lugar de usar la reflexión en tiempo de ejecución. Hago esto usando FreeMarker / FMPP; Hay muchas otras herramientas para elegir. La ventaja de esto es que terminas con un código "real" que se puede depurar fácilmente, etc.
Dependiendo de la situación, esto puede ayudarlo a hacer un código mucho más rápido, o simplemente una gran cantidad de código. Evita las desventajas de la reflexión:
mencionado anteriormente.
Si la reflexión se siente como hacer trampa, puede ser porque la estás basando en muchas conjeturas de las que no estás seguro, y tu instinto te advierte que esto es arriesgado. Asegúrese de proporcionar una manera de mejorar los metadatos inherentes a la reflexión con sus propios metadatos, donde puede describir todas las peculiaridades y casos especiales de las clases del mundo real que pueda encontrar.
fuente
No es trampa, pero como cualquier herramienta, debe usarse para lo que se pretende resolver. La reflexión, por definición, le permite inspeccionar y modificar el código a través del código; Si eso es lo que necesita hacer, entonces la reflexión es la herramienta para el trabajo. La reflexión tiene que ver con el metacódigo: el código que se dirige al código (a diferencia del código regular, que se dirige a los datos).
Un ejemplo de buen uso de la reflexión son las clases de interfaz de servicio web genéricas: un diseño típico es separar la implementación del protocolo de la funcionalidad de la carga útil. Entonces tienes una clase (llamémosla
T
) que implementa tu carga útil, y otra que implementa el protocolo (P
).T
es bastante sencillo: para cada llamada que desee hacer, simplemente escriba un método que haga lo que se supone que debe hacer.P
, sin embargo, necesita asignar llamadas de servicio web a llamadas de método. Hacer que este mapeo sea genérico es deseable, ya que evita la redundancia y lo haceP
altamente reutilizable. Reflection proporciona los medios para inspeccionar la claseT
en tiempo de ejecución y llamar a sus métodos basados en cadenas pasadas aP
través del protocolo de servicio web, sin ningún conocimiento de la clase en tiempo de compilaciónT
. Usando la regla 'código sobre código', uno puede argumentar que la claseP
tiene el código en claseT
como parte de sus datos.Sin embargo.
Reflection también le brinda herramientas para sortear las restricciones del sistema de tipos del lenguaje: en teoría, podría pasar todos los parámetros como tipo
object
y llamar a sus métodos a través de reflexiones. Voilà, el lenguaje que se supone que impone una fuerte disciplina de tipeo estático ahora se comporta como un lenguaje tipado dinámicamente con enlace tardío, solo que la sintaxis es mucho más elaborada. Cada instancia de ese patrón que he visto hasta ahora ha sido un truco sucio, e invariablemente, una solución dentro del sistema de tipos de lenguaje habría sido posible, y habría sido más seguro, más elegante y más eficiente en todos los aspectos. .Existen algunas excepciones, como los controles de la GUI que pueden vincularse a varios tipos de fuentes de datos no relacionadas; exigir que sus datos implementen una determinada interfaz para que pueda vincular los datos no es realista, y tampoco es que el programador implemente un adaptador para cada tipo de fuente de datos. En este caso, usar la reflexión para detectar el tipo de fuente de datos y ajustar el enlace de datos es una opción más útil.
fuente
Un problema que hemos tenido con Reflection es cuando agregamos Ofuscación a la mezcla. Todas las clases obtienen nuevos nombres y, de repente, cargar una clase o función por su nombre deja de funcionar.
fuente
Depende totalmente. Un ejemplo de algo que sería difícil de hacer sin reflexión sería replicar ObjectListView . También genera código IL sobre la marcha.
fuente
La reflexión es el método principal para crear sistemas basados en convenciones. No me sorprendería descubrir que se usa mucho en la mayoría de los marcos MVC. Es un componente importante en los ORM. Lo más probable es que ya estés usando componentes creados con él todos los días.
La alternativa para tal uso es la configuración, que tiene su propio conjunto de inconvenientes.
fuente
La reflexión puede lograr cosas que simplemente no se pueden hacer prácticamente de otra manera.
Por ejemplo, considere cómo optimizar este código:
Hay un golpe de prueba costoso en el medio del bucle interno, pero extraerlo requiere reescribir el bucle una vez para cada operador. Reflection nos permite obtener un rendimiento a la par con la extracción de esa prueba, sin repetir el ciclo una docena de veces (y por lo tanto sacrificar la capacidad de mantenimiento). Simplemente genere y compile el ciclo que necesita sobre la marcha.
He hecho realmente esta optimización , aunque era un poco más complicado de la situación, y los resultados fueron sorprendentes. Una mejora en el orden de magnitud en el rendimiento y menos líneas de código.
(Nota: Inicialmente probé el equivalente de pasar un Func en lugar de un char, y fue un poco mejor, pero no casi la reflexión 10x lograda).
fuente
De ninguna manera es trampa ... Más bien, permite a los servidores de aplicaciones ejecutar las clases hechas por el usuario con el nombre de su elección, por lo tanto, proporciona flexibilidad al usuario, no los engaña.
Y si desea ver el código de cualquier archivo .class (en Java), ¡hay varios descompiladores disponibles sin cargo!
fuente