Busqueda local

Loading

miércoles, 23 de febrero de 2011

Iterator Pattern I

Cuando programaba con VB 6 codificaba pseudo clases, ya que no era posible crear clases como tales, por lo que era necesario recurrir a algunas técnicas, para poder simularlo. Creábamos pseudo clases, que ahora puedo descubrir que eran cohesivas. Por ejemplo: un ticket para cobrar en algún punto de venta.
Tenía una pseudo clase Ticket, que internamente tenía una colección de Conceptos. A través del la clase Ticket exponíamos métodos para agregar conceptos a esta colección o eliminarlos, o recorrerlos para realizar cálculos, etc.
Ayer estaba buscando una forma probada para controlar este mismo escenario usando .NET, con patrones y todo eso. Y mi sorpresa fue que al encontrar el patrón Iterator, pude ver que en esencia era lo que hacíamos en aquel código.
 

Cuál es la definición de este patrón?

Es muy simple, debe proveer una forma de accesos a los elementos de alguna colección de objetos, sin que exponga la implementación interna, ni el tipo de colección que se emplea.
 

Requerimientos

Necesitamos un Ticket que pueda recibir Conceptos que pudieran ser de diferentes tipos, por ejemplo: impuestos, cargos, conceptos, subtotal, total. El código debe poder agregar conceptos, que pudieran generarse en otras clases o bibliotecas, por ejemplo: Una clase Servicio podría generar un concepto de cobro, por el uso de ese servicio en un periodo de tiempo; otra clase podría generar un concepto de cobro por algún otro concepto y este debe poder agregarse a nuestro ticket. El ticket debe ser capaz de realizar cálculos de subtotales según los diferentes tipos, así como un cálculo de total.
El reto consistía en hacer de nuevo un Ticket, pero en esta ocasión queremos algo que no sea cohesivo, que nos permitiera reutilizar e incluso hasta extender nuestra solución.
 

Solución:

Para que diferentes clases tengan una estructura en común, debemos crear una interface para los conceptos, de esta forma las diferentes bibliotecas que necesiten crear conceptos solo tendrían que implementar esta interface, en una clase de concepto.
De esta forma nuestro Ticket podría recibir todos los conceptos que implementen esta interface, sin importar la biblioteca.
La generación de conceptos puede solucionarse usando el Factory Pattern, y los requerimientos del Ticket con el Iterator Pattern.
 

Manos a la obra

Primero creamos la Interface, del concepto:
iterator1
En este punto debemos hacer un análisis de la implementación que más conviene realizar. Si el código de los conceptos tiene lógica que puede ser común, se recomienda crear una clase abstracta, donde se codifique dicha lógica y así sea reutilizada por cada Clase específica. En nuestro ejemplo si hay esa lógica, así que creamos la clase abstracta:
iterator2
Lo siguiente es crear las diferentes clases que se instanciaran por nuestro Factory, cada una es de un tipo diferente, todas heredando la clase abstracta, que a su vez implementa la interface.
Para el tipo estamos usando el patrón Enum que presente en un post previo.
Acto seguido codificamos nuestro Factory, como se expuso en un post previo:
iterator3
Se omitieron los casos, para simplificar el ejemplo, pero en el post del Factory pueden ver uno completo.
En este punto estamos listos para crear nuestro ticket. Con la misma idea de preparar nuestro código para que pueda ser implementado en diferentes bibliotecas, empezaremos por crear una interface:
iterator4
En esta interface hay dos grupos de métodos y propiedades, las primeras son para implementar el patrón Iterator y las segundas son para poder atender las necesidades de nuestro ticket.
Antes de empezar debemos comentar brevemente lo siguiente: Cuando se crea una clase en .NET para implementar el Iterator Pattern, se espera que podamos usarla con un For Each, ya que es la forma recomendada para ocultar la complejidad de un Enumerator. .NET nos ofrece la interface genérica IEnumerator<T>, la cual implemente solo dos métodos Current y MoveNext.
Debido a esto nuestro ticket debe implementar la interface ITicket que codificamos antes y además el IEnumerator de Concepto.
Nuestra clase ticket quedaría declarada de esta manera:
Iterator5
Al implementar la interface del Ticket debemos codificar sus métodos y propiedades, cada una con un objetivo especifico; para nuestro ejemplo usaremos el List genérico, por su versatilidad al codificar.
Continuar –>

No hay comentarios:

Publicar un comentario