Virtualidad vs. Eventos
El otro día, un amiguete desarrollador, me escribia lo siguiente:
"Estoy discutiendo con Manolo una cosa sobre que es mejor, te cuento nuestro problema:
Tenemos un formulario base, que realiza una serie de acciones, y tengo un método de insertar que para todos los formulario lo hace igual.
El resto de los formularios los heredamos del formulario base, pues bien, queremos poden, en algún caso especial, que después de la inserción en el formulario hijo se hagan una serie de acciones. Yo digo que es mejor crearse en la clase base un método virtual y sobreescribirlo, en una clase hija. Manolo dice que es mejor tener un evento y un delegado.
¿Puedes aclararnos quien de los 2 tiene razón?"
Esta pregunta suele ser habitual, por eso público esta entrada. Por eso y porque quiero conocer vuestra opinión. Hay una serie de situaciones donde saber si es mejor usar un método virtual o un evento es dificil.
Yo respondí lo siguiente:
"Que cosas tiene la vida...
Los dos tenéis razón y los dos estáis equivocados... interesante paradoja no...
¿Por qué los dos tenéis razón?: Los dos mecanismos son muy similares. La diferencia es sutil. Si buscas un mecanismo para modificar el comportamiento de una clase mediante herencia el camino es la virtualidad, si buscas un camino para que otras clases se enteren que esta haciendo tu clase eso es un evento. Lo dicho hasta ahora ya lo sabéis... la clave está en que el evento no permite sobreescribir totalmente el comportamiento, y el método virtual sí, si necesitáis esto yo usaria virtualidad (se trata de algo similar al clásico patrón strategy).
Véis que hay una clara cuestión semantica: si publicas un evento estás diciendo: quiero que mi clase le cuente cosas al mundo, si publicas un método virtual estás diciendo al mundo que puede modificar el comportamiento de tu clase y que ha sido diseñada para soportar esa posibilidad. ¿Qué es lo que queréis comunicar a quien use vuestra clase?.
Otra cuestión relevante es que ambos mecanismos permiten cambiar el comportamiento de la clase base, cambiar que ocurre en ciertas ocasiones... pero la virtualidad exige heredar y por tanto es un mecanismo que solo se resuelve en tiempo de compilación, sin embargo el evento se puede subscribir y desubscribir a voluntad en tiempo de ejecución, quzás necesitéis esa capacidad en algún escenario.
¿Por qué los dos estáis equivocados en cierto modo?: Por qué no sol soluciones excluyentes entre sí. Quizás la mejor solución sea usar un evento. Paradojico ¿no? Os cuento el porqué: el patrón de .net para implementar eventos dice que todo evento debe tener asociado un método protegido virtual que permita sobrescribir en clases derivadas el comportamiento de invocación del evento.
Conclusión: Si tiraís por el evento, tenéis que tener también un método virtual, o sea, lo dos ganáis. Tenéis los dos mecanismos y dáis, con casi nulo esfuerzo, mayor flexibilidad a los que usen vuestra clase.
Lo mejor del caso es que con el evento, además estáis implementando dos patrónes: polimorfismo (mediante virtualidad) y observación (mediante el evento), de tal manera que es quien usa la clase quien elige que mecanismo es el que más se adecua en cada situación.
Otra opción sería usar IoC y un inyector de dependencias, tipo Unitiy, pero creo que eso es, en este caso, harina de otro costal. Un inyector de dependencias os permitiria cambiar el comportamiento mediante configuración, sin tocar el código, pero no creo que esto sea lo necesitáis. Aunque sea la solución de moda."
¿Compartís mi visión del asunto? ¿Qué soléis preferir en situaciones de este tipo, virtualidad o eventos?. Solo como comentarío añadido decir que mi compañero Unai es más partidario de usar solo virtualidad para el caso que nos ocupa...