Vous êtes sur la page 1sur 6

Desarrollo de una aplicacin con plugins, al estilo C#

Los usuarios de la gran mayora de aplicaciones de software modernas, generalmente con el paso del tiempo, encuentran necesidades de nuevas funciones que no estaban presupuestadas en el momento que se solicit el diseo e implementacin del programa. Y por su lado los desarrolladores buscan satisfacer estas necesidades mediante la inclusin de gran cantidad de cdigo en los mismos. La solucin, por lo general, consiste en incluir gran cantidad de estructuras condicionales del tipo if else y switch case, pero lamentablemente esta estrategia no es la mejor ya que requiere estar modificando y compilando la aplicacin cada vez que se necesite adicionar una nueva funcionalidad, y esto con el pasar del tiempo puede convertirse en un dolor de cabeza para los encargados del mantenimiento. La mejor solucin, al problema de la extensibilidad y la personalizacin de una aplicacin, consiste en utilizar una arquitectura abierta donde sea posible incluir componentes externos que implementen las nuevas funciones que se necesitan, sin que el usuario requiera instalar una nueva versin de su programa. Incluso puede ser necesario dejar abierta la posibilidad de que las nuevas funcionalidades no solo sean implementadas por un nico equipo de desarrollo sino por otros expertos que tengan mayor experiencia en un campo especfico. Para desarrollar la arquitectura de una aplicacin que requiera extensibilidad y personalizacin es necesario disear una infraestructura de complementos, o lo que estamos acostumbrados a identificar como plugins. Un complemento o plugin es un componente de software que tiene la posibilidad de entregarse e instalarse por separado, y que consiste de unos o varios archivos que son ledos y cargados por la aplicacin principal para agregar nuevas funciones o modificar las ya existentes. El diseo y programacin de este tipo de aplicaciones requiere de un mayor grado de anlisis y generalizacin, lo cual se traduce en mayor esfuerzo por parte del equipo de desarrollo, pero los resultados bien lo valen ya que se obtienen productos de software con un alto grado de versatilidad y sobre todo de fcil mantenimiento. En este artculo vamos a explicar una de las formas de programar una aplicacin que acepta complementos. Nuestra aplicacin, muy elemental por cierto, estar conformada por una ventana con una barra de men que incluye los tems Archivo y Complementos. Lo primero que haremos es desarrollar la infraestructura de software que acepta los complementos. El estilo utilizado en este primer artculo deja de lado muchos detalles tcnicos en pro de facilitar la comprensin por parte del lector. Inicie una nueva solucin en SharpDevelop, de la categora Aplicaciones de Windows, y denomnela VisorImagenes. Agregue un control MenuStrip y sobre l agregue los mens Archivo y Complementos.

El men Archivo solo estar conformado por el comando Salir, que obviamente sirve para salir de la aplicacin. Seleccione el item Salir y presione la tecla F4 para visualizar sus propiedades. Ubique la propiedad Name de este item y asignele el identificador menuArchivoSalir, y por ltimo seleccione el icono Events de la ventana Propiedades para asignar un controlador al evento Click. La programacin del comando Salir quedar como se muestra en el siguiente cdigo:
void MenuArchivoSalirClick(object sender, EventArgs e) { this.Close(); }

Como es obvio, no vamos a desarrollar un visor de imgenes, sino nicamente una interfaz grfica de usuario que nos muestra la forma de cargar un plugin. Suponemos que en el men Complementos se cargarn todos los comandos que ejecuten las funciones incorporadas en los complementos. Estos se cargarn en la aplicacin al momento de iniciar la ejecucin de la misma y estarn almacenados en ensamblados del tipo librera dinmica dll. Para ello vamos a suponer que los complementos se instalan en el subdirectorio Plugins incluido en el directorio donde se encuentra el ejecutable de la aplicacin. Cada complemento ser identificado por una clase que se encuentra implementada dentro de un ensamblado. Desde el punto de vista de la aplicacin principal, es necesario realizar dos tareas bsicas: identificar los ensamblados y leer su contenido. Para la identificacin de los archivos ensamblados es necesario utilizar mtodos de manejo de directorios y archivos, y esto lo implementan clases contenidas en el espacio de nombres System.IO. Para leer el contenido de los ensamblados se utiliza el concepto llamado reflexion, cuya funcionalidad la dan las clases contenidas en el espacio de nombres System.Reflection. Por lo tanto es necesario que en el encabezado del archivo fuente del formulario se agregue estas dos lneas using:
using System.Reflection; using System.IO;

El siguiente paso es definir un mtodo void que se encargue de cargar los complementos y actualizar el men respectivo. Este mtodo ser llamado desde el evento Load del formulario, por lo tanto de inicio se tendr la siguiente codificacin:
void MenuArchivoSalirClick(object sender, EventArgs e) { this.Close(); } void MainFormLoad(object sender, EventArgs e) { CargarComplementos(); } void CargarComplementos() { // Aqu se cargan los complementos }

A continuacin vamos a implementar el mtodo CargarComplementos. Se empieza determinando el subdirectorio donde se encuentra los archivos de los complementos y hemos supuesto que esto sea Plugins. En caso de que este directorio no exista, como puede ser en la primera ejecucin, el programa deber crearlo, para evitar posibles errores en lo que resta de la ejecucin. El siguiente codigo se encarga de esta tarea:
// Aqu se cargan los complementos string directorioPlugins = Application.StartupPath + @"\Plugins"; // Si no existe el directorio de plugins, debe crearse if (!Directory.Exists(directorioPlugins)) { Directory.CreateDirectory(directorioPlugins); }

El siguiente paso es cargar los archivos ensamblados que contienen a los complementos. Como estos pueden ser ms de uno, o incluso no existir, es necesario cargar sus nombres en un arreglo del tipo string para luego examinar su contenido uno a uno. As:
// Leer los archivos ensamblados string[] archivos = Directory.GetFiles(directorioPlugins, "*.dll"); // Examinar los ensamblados uno a uno foreach(string archivo in archivos) { // Aqu se cada ensamblado }

Hasta este punto de la codificacin, aunque hemos hablado de ensamblados, en la prctica para el proceso de ejecucin no lo son, y el compilador de C# los considera nicamente como simples archivos. Es necesario dar a estos archivos la identificacin de ensamblados como tal, para de esta manera poder acceder a su contenido ejecutable. Esta tarea la realiza la clase Assembly, que se encuentra en System.Reflection, la cual se encarga de definir objetos que tienen la estructura de ensamblado al estilo .NET.
Assembly ensamblado = Assembly.GetAssembly(archivo);

Con un ensamblado como tal ya es posible examinar su contenido para determinar los tipos que lo conforman, as como sus respectivos miembros. Es importante tener en cuenta que pueden haber diferentes clases de tipos, como por ejemplos los tipos enum o los tipos class, entre otros. Para efectos de los procesos de reflexin que se necesitan en este ejercicio los nicos tipos de inters sern las clases que definen a los complementos.
// Cargar los tipos que contiene el ensamblado Type[] tipos = ensamblado.GetTypes(); // Examinar cada uno de los tipos foreach(Type tipo in tipos) { //... }

Para efectos de facilitar el desarrollo elemental vamos a suponer que cada clase contenida en un ensamblado puede definir un complemento de nuestra aplicacin sin preocuparnos por algunos detalles de acople. En el mundo real de la programacin de software de complementos es necesario definir un convenio entre la aplicacin y las clases que definen complementos, para garantizar la seguridad y la correcta integracin de los mismos. Por ahora, la nica exigencia que debe cumplir una clase para implementar un complemento ser la de definir el mtodo InicializarComplemento. Este mtodo se encargar de colocar un nuevo comando en el men Complementos y controlar el mtodo Click de este men, con un mtodo interno de la clase que define al complemento respectivo. Para ello es necesario enviarle, en un parmetro, la identificacin del men de la aplicacin que servir como punto de acceso al complemento.
// Si el tipo es una clase, instanciar un objeto if(tipo.IsClass) { // Crear una instancia de la clase Object plugin = Activator.CreateInstance(tipo); // Accesar el mtodo InicializarComplemento MethodInfo metodoInicializar = tipo.GetMethod("InicializarComplemento"); // Si el mtodo existe, ejecutarlo en la instancia creada if(metodoInicializar != null) { metodoInicializar.Invoke(plugin, new object[]{menuComplementos}); } }

El mtodo Invoke se encarga de ejecutar el mtodo al cual apunta la variable metodoInicializar, que corresponde al mtodo InicializarComplemento que deben definir todas las clases que se utilicen para implementar complementos de la aplicacin. En el segundo parmetro de Invoke se enva un arreglo con los parmetros del mtodo invocado. Para nuestro caso el nico parmetro que se necesita es el nombre de la variable que identifica al men Complementos. En definitiva, el cdigo del formulario principal queda como se muestra a continuacin:
using using using using using using System; System.Collections.Generic; System.Drawing; System.Windows.Forms; System.Reflection; System.IO;

namespace VisorImagenes { public partial class MainForm : Form { public MainForm() { InitializeComponent(); } void MenuArchivoSalirClick(object sender, EventArgs e) { this.Close(); } void MainFormLoad(object sender, EventArgs e) { CargarComplementos(); } void CargarComplementos() { // Aqu se cargan los complementos string directorioPlugins = Application.StartupPath + @"\Plugins"; // Si no existe el directorio de plugins, debe crearse if (!Directory.Exists(directorioPlugins)) { Directory.CreateDirectory(directorioPlugins); } // Leer los archivos ensamblados string[] archivos = Directory.GetFiles(directorioPlugins, "*.dll"); // Examinar los ensamblados uno a uno foreach(string archivo in archivos) { // Aqu se examinan los ensamblados Assembly ensamblado = Assembly.LoadFile(archivo); // Cargar los tipos que contiene el ensamblado Type[] tipos = ensamblado.GetTypes(); // Examinar cada uno de los tipos foreach(Type tipo in tipos) { // Si el tipo es una clase, instanciar un objeto if(tipo.IsClass) { // Crear una instancia de la clase Object plugin = Activator.CreateInstance(tipo); // Accesar el mtodo InicializarComplemento MethodInfo metodoInicializar = tipo.GetMethod("InicializarComplemento"); // Si el mtodo existe, ejecutarlo en el objeto if(metodoInicializar != null) { metodoInicializar.Invoke(plugin, new object[]{menuComplementos}); } } } } } } }

Como es de esperarse, el ejecutar por primera vez la aplicacin, no sucede nada especial, adems de cargar la ventana principal y mostrar la barra de men con el men Complementos vaco. Ahora viene el desarrollo de los complementos que necesita nuestra supuesta aplicacin de imgenes. Inicie una nueva solucin de la categora C#, y seleccione la plantilla Biblioteca de clases. Denomine a la solucin con el nombre PluginJPG. Una vez creada la plantilla, agregue una referencia al espacio de nombres System.Windows.Forms, mediante el comando Agregar referencias del men Proyecto. Para implementar un complemento para el manejo del formato de imgenes JPG modifique la plantilla del proyecto con el siguiente cdigo.
using using using using System; System.Collections.Generic; System.Windows.Forms; System.Drawing;

namespace PluginJPG { /// <summary> /// Implementa el plugin para el formato JPG. /// </summary> public class FormatoJPG { string nombre = "Formato JPG"; public FormatoJPG() {} // Implementacin del mtodo que carga el complemento public void InicializarComplemento(ToolStripMenuItem menuComplementos) { menuComplementos.DropDownItems.Add(nombre, null, MenuFormatoJPGClick); } // Mtodo que controla el evento Click del men void MenuFormatoJPGClick(object emisor, EventArgs e) { MessageBox.Show("Este es el plugin para manejar imgenes JPG", nombre, MessageBoxButtons.OK, MessageBoxIcon.Information); } } }

Ahora genere el ensamblado con el comando Generar solucin del men Generar. Lo ltimo es instalar el plugin en el directorio de bsqueda de la aplicacin principal. Ubique el ensamblado PluginJPG.dll en el subdirectorio Debug del directorio donde se haya guardado la solucin.

Copie el ensamblado y pguelo en el directorio Plugins de la aplicacin VisorImagenes.

Al ejecutar la aplicacin contenida en el ensamblado VisorImagenes.exe de la carpeta Debug observaremos que aparece el comando Formato JPG en el men Complementos.

El lector debera desarrollar otros cuantos mulos de plugins y agregarlos a la aplicacin para comprobar su funcionalidad, es decir que se registran en el men Complementos de la aplicacin. Aunque esta forma de diseo de una aplicacin extensible y personalizable funciona, es necesario realizar algunos ajustes importantes que garanticen la seguridad de los componentes y de la aplicacin que hace uso de ellos. En este punto, cuando ya nos enfrentamos a problemas reales y prcticos del desarrollo de aplicaciones de software, entran a jugar un papel muy importante algunos conceptos de programacin orientada a objetos que muchas veces creemos tienen poca o ninguna importancia como lo son las interfaces y las clases abstractas. Otro elemento importante que aporta el marco de trabajo .NET a este aspecto son los atributos. En los siguientes artculos se abordaran ms en detalle este y otros conceptos para el desarrollo efectivo de aplicaciones extensibles y personalizables con complementos.

Vous aimerez peut-être aussi