Skip Ribbon Commands
Skip to main content

Arturo Morales

:

Home
Blog de Arturo Morales
June 24
Quiero que haga Undo!... ¿Que haga que?!

Como mi primer post que es, empezaré con algo sencillo. Una implementación de una tarea tan conocida como desarrollar un Undo.

 

Si os dais cuenta desde que ha salido Silverlight quizá todos los que últimamente nos hemos centrado mucho en desarrollar aplicaciones web a medida, debamos empezar a hacernos planteamientos en el diseño de nuestras aplicaciones, similares a los que nos hacíamos con las aplicaciones de escritorio tradicionales, en las cuales trabajábamos en un entorno en el que buscábamos hacer el mínimo número de llamadas a servidor posible.

 

No quiero decir que no buscásemos esto en una aplicación ASP.NET convencional, si no que con Silverlight se nos ha abierto un número increíble de posibilidades en el desarrollo web que antes eran muy difíciles de plantearse.

 

Proveer al usuario de un sistema en el cual pudiera deshacer cambios de su trabajo un número determinado de veces sería un ejemplo de lo difícil y poco mantenible que sería implementar esto en una aplicación web y de lo “sencillo” que sería con un lenguaje orientado a objetos como C#.

 

Bueno empecemos. Lo primero que tenemos que hacer antes de plantearnos cómo hacer que nuestra aplicación haga tal o cual cosa es buscar y preguntar si alguien ha hecho algo similar y naturalmente en este caso (y en la mayoría) la respuesta es sí.

 

Existe un patrón de diseño específico para esto que es el patrón Command. El patrón Command no es más que encapsular las operaciones que deseemos realizar en clases que implementan una clase abstracta la cual tiene un método Execute y un método Undo. Cada vez que queramos desarrollar tal o cual operación en nuestra aplicación, si implica un cambio del conjunto de datos con el que trabajamos debemos pensar en un comando que realice esta acción. El comando en sí guardará el estado en el que se encuentran los datos justo antes de comenzar a ejecutarse pudiendo devolver dicho estado mediante el método Undo.

 

Además, pensando en comandos, debemos ser conscientes de que se pueden anidar construyendo operaciones complicadas a partir de otras más sencillas y testeadas dando más robustez a nuestra aplicación.

 

Empecemos por partes. Debemos implementar una clase abstracta de la que deriven las implementaciones concretas que queramos desarrollar, como agregar una entidad, borrar una entidad, calcular el coeficiente entre la inversión de lo que sea y hacer el pino puente después o cualquier otra cosa. Así que lo que debiéramos hacer es lo más sencillo de todo que es esto:

 

Todas las implementaciones de esta clase tendrán un método Execute el cual  se encargará de guardar el estado antes de la ejecución de la tarea.

 

Sigamos diseñando. Por un lado si ponemos Execute como virtual siempre debiéramos hacer el dichoso base.Execute(); antes de implementar las operaciones del comando en el método override del Execute. Así que vamos a hacer dos clases base:

 

·         Cmd que será un cascarón vacío con el método abstracto Execute

·         y  CmdBase sellará la implementación de Execute y dentro de él llamará un método abstracto y protegido doExecute que los diferentes comandos concretos deberán implementar.

 

Con esto podemos realizar pre-acciones (como guardar el estado) y post-acciones (como lanzar un evento de fin de ejecución). Además quiero que el estado se defina por un tipo que puede ser un DataSet una entidad custom que englobe otras, una entidad root de entityframework, etc. Así que hacemos una clase genérica o de plantilla… pero aún no he terminado! ¿Encapsulamos en una clase el proceso de guardar el estado? Pues mejor sí porque así podemos centralizar esta operación que en nuestro caso va a ser una serialización binaria de la entidad, pero que en otros casos más serios se puede complicar bastante realizando métodos de clonado, etc. con el fin de mejorar el rendimiento de los comandos.

 

Nos quedaría algo así:

 

 

 

 

 

Esto ya empieza a quedar bonito J claro y útil.

 

Bien pues ya tenemos el diseño básico de los comandos, y ahora tenemos que administrar los comandos para que el usuario pueda hacer el dichoso Undo.

 

Nos implementamos una clase manager que va ha contener en una pila de tipo CmdBase la cual por un lado almacenará los comandos ejecutados y por otro nos proveerá de un método Undo el cual ya se encargará de sacar el comando de la pila y devolver su estado.

 

Al mismo tiempo rizamos el rizo y pensando que la aplicación puede visualizar diferentes secciones “Undoables” hacemos un manager del manager que según el tipo de la entidad nos puede devolver uno u otro manager. Así que nos salen dos clases una que es el manager específico por el tipo de entidad a manejar y otro que es el que engloba los demás. En el ejemplo que os he subido solo trato con un tipo de manager pero hacer que el manager global trate con varios managers hijo es muy sencillo.

 

Bueno nuevamente os muestro el diagrama de clases.

 

Y bueno pudiera explayarme mucho más pero creo que lo mejor es que os deje un ejemplo muy sencillito que he implementado con un comando de alta y otro comando de baja y que le echéis un vistazo al código. Tira contra la bbdd de ejemplo de AdventureWorks (la de toda la vida) que la podeis descargar de microsoft.

 

Aquí teneis el código.

 

Nos es nada nuevo pero me ha parecido bonito y útil hablar de esto y espero que os haya gustado.

 

 

 About this blog

 
About this blog
Welcome to SharePoint Blogs. Use this space to provide a brief message about this blog or blog authors. To edit this content, select "Edit Page" from the "Site Actions" menu.