En equipo se trabaja mejor
Login
Registrarse (gratis)

HOME

El MUG

Eventos

Noticias

Comunidad MUG

VB - VB.Net

C#

J#

Desarrollo Web

SQL - DB

FoxPro - Gufa

Infraestructura

Patrones


Artículos


Curso

.NET

Foros y listas

Descargas

Links útiles

Quiénes Somos

Privacidad

Beneficios

Contáctanos

Proyectos

Córdoba

Rosario

Toda la Tecnología Microsoft y Mas
Patrones en .NET
Introducción al tema de Patrones, con implementaciones en .NET
Publicado por el Wednesday, April 14, 2004

Código fuente usado en el artículo

Artículo original en www.ajlopez.com

Cuando construimos una pieza de software, desde un pequeño utilitario, hasta un sistema completo distribuído, estamos encarando un trabajo de análisis, diseño y desarrollo. Esa actividad puede realizarse en grupo o individualmente. En muchas situaciones, hemos notado que la implementación de una solución, en un caso de diseño o de programación, es similar a otra que hemos adoptado en el pasado. También suele suceder que descubrimos, más adelante, que la solución adoptada para un problema en particular, sea opacada por otra solución no contemplada inicialmente. Cuantas veces nos "despertamos" a una nueva alternativa de implementación, al ver el código o el esquema de la solución de otro producto. Es común encontrar también pistas e ideas interesantes en los artículos y libros que vamos consultando.

Siendo la creación de software, una actividad humana que se viene desarrollando desde hace décadas, no es extraño que hayan surgido esquemas de soluciones a problemas planteados anteriormente. Y, ante tanta "crisis del sofware", (el siempre presente problema de generar soluciones en tiempo y costo), esta situación ha incentivado la aparición de metodologías de análisis, de diseño, de implementación, y de manejo de proyectos.

En el agitado mundo de estas metodologías (reflejo de los perpetuos cambios a los que nos tiene acostumbrada nuestra profesión), a fines del siglo pasado, surge el concepto de "Patterns" (patrones). He preferido dejar el título en inglés, pues es al que nos hemos acostumbrado en estas latitudes. Veamos en este artículo, qué son estos patterns, y cómo se pueden aplicar en .NET, la nueva tecnología de Microsoft, que tanta sorpresas nos depara (desde la ansiada herencia, hasta la máquina virtual base de todo, pasando por el marco de clases comunes).

Un pequeño ejemplo

El patrón resulta ser una solución a un problema, que se puede aplicar muchas veces, en distintas situaciones. Veamos un caso en particular.

Supongamos que tenemos una clase SistemaDeFacturacion, que concentra la actividad de generar facturas. Queremos que el resto del sistema, interactúe con una sola instancia de esta clase, porque es importante para nosotros no generar recursos duplicados, y controlar el acceso a los mismos. ¿Cómo podemos conseguir este resultado?

Podemos escribir el código:

public class SistemaDeFacturacion { //NOTA: Sólo para aplicaciones de un thread private static SistemaDeFacturacion _Instancia = null; private SistemaDeFacturacion() {} public static SistemaDeFacturacion GetInstancia() { if (_Instancia==null) { _Instancia = new SistemaDeFacturacion (); } return _Instancia; } //... otras funciones de Sistema de Facturacion }

Siempre he pensado, que para entender realmente una parte del conocimiento humano, es importante conocer la historia de su desarrollo. Esto nos permite entender las motivaciones para su aparición, así como las dificultades, elecciones, y falsos caminos tomados. Y hasta quizás, participar de alguna medida, en su posterior desarrollo. De aquí, la necesidad de los siguientes párrafos.

Algo de historia

Curiosamente, el concepto de patrón de diseño, no nace en el software, sino en otra actividad, en la arquitectura (la de construcción de edificios). Como la nuestra, esta actividad se dedica a construir, y no es extraño que comparta vocabulario y conceptos.

Christopher Alexander es el arquitecto que primero estudió el concepto de pattern, en el contexto de construcción de edificios y comunidades. El escribió, ya en 1977:

"Cada pattern describe un problema que ocurre una y otra vez en nuestro entorno, y además, describe el núcleo de la solución a ese problema, de tal manera, que podemos usar esa solución un millón de veces más en el tiempo, sin que tenga que ser la misma cada vez"

El escribía acerca de patterns en la arquitectura, pero lo que describe, se puede aplicar a la ingeniería del software. Expresaremos nuestra solución en términos de objetos e interfaces, en lugar de usar paredes, espacios y edificios. Pero al fin, usaremos mismos principios para expresar un pattern.

A fines de los ochenta, el término "software architecture" era ya usado normalmente, y en las reuniones de especialistas, iba naciendo la idea de un manual para arquitectos de sistemas, una especie de guía o hasta enciclopedia, de las prácticas habituales en la construcción de sistemas.

Ya había habido algún antecendente ilustre, como el conocido "The Art of Computer Programming" del notable Donald Knuth. Su intento de catalogar el conocimiento acumulado sobre la programación, estuvo centrado en los algoritmos. Aún hoy es la referencia sobre algunos de esos temas. Algunas otras publicaciones habían tratado otros aspectos. El libro seminal de Coplien "Advanced C++: Programming Styles and Idioms" (tengo en mi poder un ejemplar, realmente disfruté mucho leyéndolo), mostró ciertas soluciones específicas a C++, por ejemplo, una que permitía construir una clase String (tan necesaria en un lenguaje que derivaba de C, donde el concepto de string como tipo primitivo no existía), de una forma eficiente.

Por otra rama, en la de desarrollo en Smalltalk (más que un lenguaje o una tecnología, un ambiente de objetos), se comienzan a describir patrones, soluciones que ya se habían aplicado en problemas anteriores, notablemente en la propia librería base del lenguaje (como el caso del notify en Object, preludio de los actuales Observer). El mítico Kent Beck tuvo la idea de difundir el trabajo de Alexander, tan alejado al principio del software, entre la comunidad smalltalker, desde su columna en "The Smalltalk Report". Peter Coad también trabaja en esos tiempos en coleccionar patrones. En un escrito de 1992, "Object Oriented Patterns", en las comunicaciones de la asociación ACM (Association for Computer Machinery, http://www.acm.org), comienza a presentar el uso de patrones en las etapas de análisis y diseño.

Pero es con el trabajo de Gamma, Helm, Johnson, Vlissides, "Design Patterns", en 1995, subtitulado "Elementos de software orientado a objetos reusable", cuando el tema se pone maduro. Estos autores, conocidos afectuosamente como "GoF" (la "Gang of Four", la banda de los cuatro), son los que toman el trabajo algo monumental, de hacer un catálogo de los patrones de diseño que hasta ese momento habían aparecido, y en una lista de 23 patterns, tratan de enumerar el conocimiento acumulado sobre el tema. Este libro (también en mi biblioteca, uno de esos libros a salvar de un incendio, junto con el Rey Pastor, y alguno como los "Elementos de Historia de las Matemáticas" de Bourbaki), se ha convertido en un escrito de culto para los estudiosos, y realmente se lo merece, por el orden y la claridad y extensión de su exposición.

¿Qué es un Design Pattern?

Pero basta ya de introducción histórica, pasemos a describir qué es un patrón de diseño (que no es la única clase de patrón existente, pero es el más conocido).

Más arriba, hemos encontrado una cita de Alexander, donde menciona que un pattern, es "la solución a un problema". Según "GoF" un patrón tendrá entonces, cuatro elementos esenciales:

- El nombre: Este elemento, que alguien podría pensar que es intrascendente, o trivial, ha probado que ser fundamental. A cada patrón popular, se le ha asignado una denominación que permite que los entendidos en el tema, puedan conversar usando un diccionario común. Nos permite un mayor grado de abstracción. Nos permite comunicarnos con nuestros colegas, construir un lenguaje compartido, y hasta nos ayuda a nosotros mismos, al ordenar un patrón bajo un nombre. Según "GoF", uno de los problemas que tuvieron, fue encontrar un nombre apropiado para cada patrón que catalogaron.

- El problema: acá se explica el problema original, y su contexto. Puede describir desde detalles específicos, como algoritmos, o clases y estructuras que se han encontrado inflexibles a la hora de implementarse. Pero primero, todo patrón nace de un problema a solucionar.

- La solución: nos encontraremos, en nuestro estudio de los patrones, que cada uno es en realidad una solución a un problema, el elemento planteado arriba. Hasta puede que un mismo problema real, tenga dos soluciones parecidas, correspondientes a dos patrones (muchas veces pasa esto con el Abstract Factory, versus el Factory Method). Pero la elección seguramente recaerá en el patrón que mejor se adapte al contexto particular del problema que tengamos entre manos. Resaltemos que la solución que un patrón describe, no necesariamente es detallada al nivel de implementación, sino que provee una descripción abstracta, una enumeración de elementos y sus relaciones, para solucionar el problema planteado.

- Las consecuencias: son los resultados de aplicar el patrón, los "trade-off", compromisos, que se tienen que aceptar al adoptar el mismo. Como dicen los americanos, "no free lunch", no hay almuerzos gratis, de alguna forma hay que pagar lo que aparece especialmente barato. En general, en software, la moneda de pago de pago es el espacio y el tiempo. A veces, un patrón nos soluciona un tema de espacio (como el Flyweight), a costa de una mayor complejidad en otra punta de nuestro desarrollo.

Hay algo a esta altura del artículo para destacar: vemos que un patrón siempre tiene un problema, y una solución. Pero también notemos, que los catálogos de patrones que han aparecido, destacan que los elementos clasificados, siempre son patrones que ya se han aplicado exitosamente con anterioridad. No se ha dado el caso de un patrón creado de la nada, o simplemente para engrosar el catálogo. Cada patrón que veamos en la literatura, se verá respaldado por aplicaciones anteriores. El trabajo del catalogador, ha sido descubrir la esencia del patrón, para poder describirlo en un nivel mayor de abstracción, y aprovechar así su poder en otros ámbitos y contextos parecidos.

Describiendo un Pattern

He aquí algunos un formato consistente, para describir un patrón, adoptado en el libro de Gamma:

Nombre del patrón y clasificación

Cada patrón tiene un nombre, y una categoría a la que pertenece. El "GoF" los clasifica en creacionales, estructurales y de conducta. Más sobre esta clasificación más adelante.

Intención

Nada se da en la nada, sino en un contexto. Cada patrón tiene una intención, una razón, una justificación, algo como "¿qué problema de diseño trata de abordar?"

Otros nombres

O el A.K.A. ("Alsa Known As") del patrón. Ahora menos usado, pero en su tiempo, los patrones habían surgido en distintos proyectos y tecnologías. Los primeros autores les dieron un nombre que no siempre coincidía. Estos otros nombres pueden ser enumerados en la descripción del patrón.

Motivación

Más que la intención, esta parte describe un escenario: un problema en particular que aparece, y que ayuda a entender la descripción algo más abstracta del patrón genérico.

Aplicación

En qué situaciones puede ser aplicado un patrón. Pueden darse ejemplos de malos diseños, que pueden beneficiarse de la aplicación de este patrón en particular.

Estructura

La parte más conocida, luego del nombre. Se adopta un diagrama basado originariamente en la OMT ("Object Modeling Technique"), hoy se usa UML ("Unified Modeling Language", Lenguaje Unificado de Modelado). Si bien no se necesita entender al detalle esta notación, cuando aparezca, en este artículo daremos nociones de la misma.

Partipantes

La lista de las clases y objetos que participan del patrón de diseño, y las responsabilidades que tienen.

Colaboraciones

Descripción de cómo los participantes colaborar para llevar a cabo sus responsabilidades en el patrón

Consecuencias

Explica cómo el patrón cumple con sus objetivos, y que compromisos se asumen.

Implementación

Esta es la parte que más puede variar, porque para cada patrón puede haber varias posibles implementaciones, incluso, diferentes implementaciones según la tecnología adoptada. Veremos que hasta puede haber sutiles diferencias entre una implementación y otra, ligadas, por ejemplo, al lenguaje de implementación.

Código de ejemplo

Los buenos de la "GoF", siempre nos dan código de ejemplo de cada patrón, por ejemplo, en Smalltalk o en C++. Han aparecido luego libros con patrones aplicados a Java, y comienzan a aparecer las implementaciones .Net.

Usos conocidos

Un patrón no es tal, si no ha sido ya empleado en algún caso real. Se debe incluir por lo menos dos ejemplos conocidos de difentes ámbitos.

Patrones relacionados

Ya hemos apuntado que un patrón es una solución a un problema. Puede que haya problemas parecidos, que tengan más de una solución. De ahí que muchos patrones estén relacionados entre sí: como el caso del Proxy y del Adapter. Se trata de explicar acá cuáles son las similitudes y (no menos importante) las diferencias, entre patrones relacionados.

Clasificación de Patrones

Gamma y sus colaboradores, se concentran en los patrones de diseño, y los clasifican en las categorías. Agreguemos un resumen de los patrones que encontraron en cada una.

Patrones Creacionales

("Creational Patterns") Abstraen el proceso de instanciación. Nos ayudan a independizar a un sistema, de cómo sus objetos son creados. En general, tratan de ocultar las clases y métodos concretos de creación, de tal forma que al variar su implementación, no se vea afectado el resto del sistema.

Es común encontrar "competencia" entre estos patrones: hay más de un patrón a adoptar ante una situación.

Hay varios ejemplos en .NET de aplicación de estos patrones. Podemos nombrar acá al WebRequest.Create, que nos devuelve un objeto de distintas clases, dependiendo de lo que le aportemos como parámetros en ejecución.

Abstract Factory: Nos da una interface para crear objetos de alguna familia, sin especificar la clase en concreto.

Builder: Separa la construcción de un objeto complejo, de su representación. De esa manera, el mismo proceso de construcción puede crear diferentes resultados.

Factory Method: Se define una interface para crear objetos, como en el Abstract Factory, pero se delega a las subclases implementar la creación en concreto.

Prototype: Mediante una instancia prototípica, conseguimos otras instancias de ese objeto.

Singleton: Nos consigue dar un solo objeto de la clase, en cualquier momento de la aplicación.

Estructurales

:

("Structural Patterns") Se ocupan de cómo clases y objetos se agrupan, para formar estructuras más grandes. Podemos nombrar al clásico patrón Composite, que permite agrupar varios objetos como si fueran uno solo, y tratar al objeto compuesto de una forma similar al simple. El clásico ejemplo es el de una clase Arbol, donde cada Nodo no importa si es un NodoCompuesto o uno simple. Encontramos en .NET una aplicación de este patrón en el XmlDocument.

Adapter: Permite convertir una interface de una clase, en otra, que es la esperada por algún cliente.

Bridge: Desacopla una abstracción de su implementación en concreto. Luego, podemos cambiar la implementación, o la abstracción, sin cambiar la otra.

Composite: Compone objetos en una estructura de árbol, donde los objetos compuestos se tratan de forma similar a los objetos simples.

Decorator: Agrega responsabilidad a un objeto dinámicamente, dándonos una alternativa a la extensión de una clase, en lugar de usar subclases.

Facade: Provee una interface unificada a un conjunto de funciones de un subsistema. Es una interface de alto nivel, para facilitar el uso del subsistema.

Flyweight: Permite compartir objetos, sin repetirlos en el sistema, eficientemente.

Proxy: Provee un subrogado a otro objeto, para controlar el acceso al mismo.

De Conducta

:

("Behavioral Patterns") Más que describir objetos o clases, sino la comunicación entre ellos. Frecuentemente, describen las colaboraciones entre distintos elementos, para conseguir un objetivo. Como muestra, en .NET tenemos los Enumerator, que implementan el patrón Iterator, una forma de recorrer una lista o colección, sin afectar a este elemento.

Chain of Responsability: Nos desacopla el enviador de un mensaje, de su receptor, permitiendo que haya varios objetos que tengan la oportunidad de manejar el requerimiento. Eso se consigue pasando el requerimiento por la cadena de objetos hasta llegar al encargado de atenderlo.

Command: Encapsula el requerimiento a un objeto, permitiendo incluso el "undo" de la operación.

Interpreter: Construye una representación de la gramática de un lenguaje, junto con su intérprete.

Iterator: Nos da un modo de acceder a los elementos de un objeto colección o similar, sin exponer su estructura interna.

Mediator: Permite la interacción de varios objetos, sin generar acoples fuertes en esas relaciones.

Memento: Sin necesitar entrar en la estructura interna de un objeto, permite capturar su estado, para, por ejemplo, poder restaurarlo más adelante.

Observer: Define una relación uno a muchos, entre un objetos y otros que están interesados en sus cambios, de nuevo, sin caer en el acople entre los mismos.

State: Permite a un objeto cambiar su conducta cuando cambia su estado interno, simulando que cambia de clase.

Strategy: Define una familia de algoritmos, y los hace intercambiables.

Template Method: Define el esqueleto de una operación, cuyas operaciones más básicas, quedan delegadas en subclases.

Visitor: Nos permite recorrer una estructura (un árbol, por ejemplo), aplicando una operación a cada elemento.

Para cada uno de estos, el libro mencionado da un detalle exhaustivo, incluyendo código de ejemplo, e implementaciones conocidas.

Analicemos entonces, más en detalle, algunos de estos patrones, desde el punto de vista de .NET.

El patrón Singleton

Habíamos mostrado un ejemplo de patrón, llamado Singleton. Ahora describámoslo de forma más acorde a lo que se habitúa en la literatura.

Contexto

En algunas situaciones, necesitamos que algunos datos sean accesibles desde el resto del sistema. Y también necesitamos que esos datos sean únicos. Por ejemplo, un objeto que abstraiga lo que es el Sistema Operativo actual. También podría ser un objeto que represente al Sistema Contable, que sea el punto de entrada a un sistema externo.

Problema

¿Cómo hacer que la instancia de un objeto sea accesible globalmente, y que sea única?

Fuerzas

Consideremos las fuerzas que intervienen en las posibles soluciones.
- Hay lenguajes que soportan la existencia de variables globales, como Visual Basic 6, o Visual C++. En estos lenguajes, esa variable reside en la espacio de nombre raíz, y pueden ser accedidas desde cualquier otra parte del sistema. Esto puede solucionar el requerimiento de que sea visible globalmente, pero no el de instancia única. Hay otros lenguajes que no tienen el concepto de variable global.
- Si necesitamos que la instancia sea única, debemos tener control de la creación de las instancias de la clase. Habrá que implementar algún mecanismo para que no cualquiera pueda crear una instancia.

Solución

El patrón Singleton proporciona la siguiente solución:

- Hacer que la clase provea una instancia de sí misma.
- Permitir que otros objetos obtengan esa instancia, mediante la llamada a un método de la clase.
- Declarar el constructor como privado, para evitar la creación de otros objetos.

El diagrama UML correspondiente es muy simple:

Este diagrama UML muestra que Singleton es una clase. Contiene una propiedad estática (el subrayado indica que es un método de clase, mas que de instancia), que retorna un Singleton, un objeto de la misma clase. Según la notación UML el número 1 en la esquina superior derecha, indica que solamente habrá una instancia de esta clase. El signo "-" en el constructor, lo señala como privado. Esto consigue que nadie aparte de la propia clase, pueda crear una instancia.

Implementación

Public Class Singleton Private Shared mInstance As Singleton Private mTime As String ' Constructor privado Private Sub New() mTime = Now.ToLongTimeString MsgBox("Objeto Singleton Creado en New") End Sub Public Shared Function GetInstance() As Singleton If mInstance Is Nothing Then mInstance = New Singleton() End If Return mInstance End Function Public Function GetTime() As String Return mTime End Function End Class

Esta es una implementación en VB.NET. Notamos que el método GetInstance está marcado como "shared", siendo entonces un método de la clase.

Conseguimos que el constructor no pueda usarse desde otra parte del sistema, catalogando con "private" al Sub New.

Notemos un detalle en esta implementación, que no es parte del patrón original: deferimos la creación del objeto hasta el momento que alguien pide la instancia. Esto puede tener sus razones: tal vez no tengamos toda la información sobre cómo crear el objeto, hasta el momento apropiado.

Como toda implementación, puede tener alguna arista sutil. La que no es evidente, en este ejemplo, es ésta: no contempla la posibilidad de dos "threads" (hilos de ejecución) que, al mismo tiempo, pidan el método GetInstance, por primera vez. Si así sucediera, podría suceder que estos dos hilos de ejecución, cada cual por su parte, encuentre en "Nothing" a la instancia interna, y hagan cada uno un "new", creando dos instancias.

Este es un ejemplo mejorado, que resuelve ese problema, usando un objeto Mutex:

Public Class Singleton Private Shared mInstance As Singleton Private Shared mMutex As New System.Threading.Mutex() Private mTime As String ' Constructor privado Private Sub New() mTime = Now.ToLongTimeString MsgBox("Objeto Singleton Creado en New") End Sub Public Shared Function GetInstance() As Singleton mMutex.WaitOne() If mInstance Is Nothing Then mInstance = New Singleton() End If mMutex.ReleaseMutex() Return mInstance End Function Public Function GetTime() As String Return mTime End Function End Class

Veamos otra implementación, esta vez en C#.

public sealed class Singleton { private static volatile Singleton instance; private static object syncRoot = new Object(); private Singleton() { System.Windows.Forms.MessageBox.Show("Nuevo Singleton"); } public static Singleton GetInstance { get { if (instance == null) { lock(syncRoot) { if (instance == null) instance = new Singleton(); } } return instance; } } }

En algunas situaciones, nos basta implementar la creación de la única instancia, en la inicialización de las variables estáticas.

public sealed class Singleton2 { private static readonly Singleton2 instance = new Singleton(); private Singleton2(){} public static Singleton Instance { get { return instance; } } }

El patrón Observer

Examinemos este patrón, y su implementación en .NET.

Contexto

Siempre que pensamos en objetos, podemos encapsular su estado y la implementación de su comportamiento. Esto permite reusarlo en otras aplicaciones, de forma natural. Pero un objeto no es un ente aislado. Es común que deba colaborar con otros para cumplir con una tarea. A veces, la colaboración es altamente acoplada: los objetos intervinientes conocen sus interfaces de antemano. En otras situaciones, algunos objetos solamente estarán interesados en los cambios que se ejecuten en otro determinado, sin que éste necesariamente tenga que conocer a los primeros. Este es el caso del patrón Model-View-Controller, que permite separar el modelo que estamos manejando, de la forma de mostrarlo (la vista). La vista (un control en un formulario, un gráfico), puede que esté interesada en conocer cuándo cambia el modelo subyacente.

Problema

¿Cómo podemos notificar a otros objetos que el estado de un objeto determinado cambió, sin depender de qué clases son?

Fuerzas que intervienen

Una posible solución, es que el objeto que cambia, llame directamente a los objetos interesados. Pero esto crea una dependencia entre ellos, que podemos evitar. Porque el acoplamiento dependiente que se crea, dificulta el reúso y complica los cambios futuros en las relaciones.

Un cambio en la vista, si adoptamos la llamada directa, podríaa afectar entonces a la programación del modelo. La necesidad de evitar esa dependencia se torna importante. Por otra parte, si tenemos que agregar una nueva vista, tendremos que modificar el código del modelo, que avisa de sus cambios.

Por otra parte, la llamada directa puede ser el método más rápido de avisar los cambios. Habrá que considerar los efectos sobre la performance de la aplicación, al adoptar un esquema menos directo.

Solución

El patrón de Observer, mantiene una lista de objetos interesados en enterarse de los cambios. Todos los interesados en observar, deben implementar una interface Observer.

En el diagrama, aparece otra interface, la Subject, que implementan todos los objetos que quieren ser observados. Al aplicar estas interfaces, nos independizamos de las clases en concreto, que más adelante pueden cambiar, sin afectar el esquema adoptado.

Una implementación de este patrón en VB.NET, es la siguiente:

Public Interface Observador Sub Notificar(ByRef obj As Object) End Interface Public Interface Sujeto Sub Registrar(ByRef eo As Observador) Sub DesRegistrar(ByRef eo As Observador) End Interface Public Class SujetoConcreto : Implements Sujeto Dim m_Observadores As New Hashtable() Public Sub Registrar(ByRef eo As Observador) Implements Sujeto.Registrar m_Observadores.Add(eo, eo) End Sub Public Sub DesRegistrar(ByRef ew As Observador) Implements Sujeto.DesRegistrar m_Observadores.Remove(ew) End Sub Public Function Procesar() Dim ProcesarTiempo As DateTime = DateTime.UtcNow Dim unObservador As Observador For Each unObservador In m_Observadores.Keys unObservador.Notificar(ProcesarTiempo) Next End Function End Class Public Class EscuchadorUno : Implements Observador Sub Notificar(ByRef obj As Object) Implements Observador.Notificar Console.WriteLine("EscuchadorUno procesa " & obj) End Sub End Class Public Class EscuchadorDos : Implements Observador Sub Notificar(ByRef obj As Object) Implements Observador.Notificar Console.WriteLine("EscuchadorDos procesa " & obj) End Sub End Class

Pero resulta algo notable, que en .NET, tengamos otra forma de implementar el patrón, que ha nacido de la capacidad de definir eventos, y escuchadores ("handlers") para esos eventos. Esa capacidad ya estaba presente de alguna forma en Visual Basic "normal", pero la implementación .NET es más flexible: más de un objeto puede escuchar un evento.

La siguiente solución, apela al uso de eventos, y delegados.

Public Class Articulo Delegate Sub DelegadoCambiaPrecio(ByVal unPrecio As Object) Public Event CambiaPrecio As DelegadoCambiaPrecio Dim _cambiaPrecio As Object Public WriteOnly Property Precio() Set(ByVal value As Object) _cambiaPrecio = value RaiseEvent CambiaPrecio(_cambiaPrecio) End Set End Property End Class Public Class ArticuloObservador Public Sub Notify(ByVal unObjecto As Object) Console.WriteLine("El nuevo precio es:" & unObjecto) End Sub End Class

Otros tipos de patrones

Microsoft, reconociendo la importancia de los patrones, ha publicado sus ideas y sugerencias sobre el tema. En los enlaces al final del artículo, encontraremos mayor información. Algo que podemos destacar ahora, es su clasificación, construída desde un punto de vista distinto. Veamos su marco de patrones:

Según Microsoft, las filas representan niveles progresivos de abstracción: arquitectura, diseño e implementación, mientras que las columnas son "puntos de vista" de la solución, perspectivas como base de datos, aplicación, instalación, infraestructura.

Entonces, según este esquema, hay más que "design patterns": los hay también de arquitectura y de implementación.

Un patrón de arquitectura, según Buschmann, es entonces:

"Un patrón que expresa un esquema de organización estructural fundamental para un sistema de software. Provee un conjunto predefinido de subsistemas, especifica sus responsabilidades, e incluye reglas y guías para organizar las relaciones entre ellos".

Discutamos un ejemplo y su patrón, en los siguientes párrafos.

Niveles de abstracción

Si bien la mayor parte de los patrones tiene su aplicación directa en código, no significa que sea el único nivel al que se manejan. Comentemos un ejemplo del sitio de Microsoft, que aplica un patrón que es muy conocido por los desarrolladores, especialmente en los últimos años.

Estamos desarrollando un sistema empresarial, donde queremos manejar la información de presupuestos para los clientes de la empresa. Necesitamos conocer los precios internos, armar el presupuesto, tener en cuenta el inventario de los productos, y contemplar los datos e historia del cliente que pide el presupuesto. La información debe estar disponible para ser consultada por la web, y provenir de distintas fuentes de datos.

Querríamos organizar la arquitectura del sistema para que sea flexible, por ejemplo, que contemple las distintas formas de acceder a los datos, y las formas de procesarlos , y por último, los distintos modos de visualizar el resultado.

Así planteado, es un especificación muy general, pero que nos sirve para presentar un patrón conocido de arquitectura: el patrón de capas.

Podemos tomar la decisión de separar la aplicación según este esquema:

Esta solución termina aplicando el patrón Layers, que tanta veces hemos encontrado (hasta se utiliza en la arquitectura de redes, donde el modelo ISO se basa justamente en dividir el trabajo en las capas de transporte, aplicación y otras).

Formalizando la definición del patrón, podemos encontrar:

Contexto

Estamos trabajando en un sistema grande y complejo. Y queremos manejar la complejidad via la descomposición.

Problema

Cómo estructurar la información para soportar los requerimientos de mantenimiento, reusabilidad, escalabilidad, y robustez.

Solución

Componer la solución en una serie de capas. Cada capa debe ocuparse de un nivel del problema, y debe tener poca cohesión con las demás.

Este patrón tiene consecuencias no evidentes: el cambio en una capa, debería alterar en poco los cambios en las otras capas. La prueba ácida, en nuestro ejemplo original, podría ser: al cambiar las fuentes de datos (las bases de datos usadas), poco debería afectar a la capa de presentación. Y si el día de mañana queremos incorporar una capa de presentación distinta (como un sistema de atención automática por teléfono, usando un IVR), no debería alterar a las otras capas ya desarrolladas. En definitiva, como en el ejemplo del modelo ISO de redes, el cambiar la implementación de una capa, debe tener los mínimos efectos en el resto de la aplicación.

Si bien en este ejemplo, las capas que elegimos armar son las de presentación, negocio y datos, el patrón es lo suficientemente general para aplicarse en otras situaciones.

Y es un patrón de arquitectura: nos da una base para el fundamento estructural de una aplicación.

Patrones de Integración

En el mundo actual de la informática, pocos sistemas viven en solitario. Cada vez más es la regla, encontrarse con aplicaciones disímiles, de distintos fabricantes, en distintas plataformas, y que no se conectan entre sí. Puede ser que el CRM de la empresa, haya sido comprado a un proveedor de IT, que está totalmente desconectado del sistema empresarial, y éste a su vez, no se comunica con el sitio web de la compañía.

De nuevo, como en los problemas de diseño y de arquitectura, los patrones acuden a la ayuda. Han comenzado a surgir los llamados "integration patterns"; o patrones de integración.

En el sitio www.integrationpatterns.com se comentan más de 60 patrones descubiertos, que ayudan a la hora de armar soluciones que integren a los sistemas empresariales. Entre los temas cubiertos, se encuentran:

Estilos de integración

Cuáles son las formas de comunicar sistemas: desde el viejo truco del archivo compartido (el sistema A graba información en un archivo, y se lo entrega al sistema B), hasta la base de datos compartida, la llamada a procedimientos remotos (ahora en .NET tenemos Web Services y Remoting), y el uso de sistemas de mensajería.

Patrones de Canal

Describen los patrones adoptados en la implementación de canales: los medios de comunicación que se emplean. Por ejemplo, el canal punto-a-punto, donde la comunicación es de una aplicación a otra establecida, versus el canal-suscripto, donde las aplicaciones interesadas se suscriben a un canal de información que otra aplicación produce.

Patrones de Construcción de Mensajes

Cuáles son los métodos de construcción de mensajes, que en definitiva, son los datos que viajan en los canales. Desde el mensaje tipo comando (similar al patrón Command), hasta el mensaje tipo Consulta (Query), pasando por el mensaje tipo Documento. O el mensaje tipo Respuesta. Todas estas formas de mensajes y su construcción ya han sido implementadas en sistemas de mensajería, y han surgido patrones de soluciones.

Patrones de Ruteo

Cómo se pueden encaminar los mensajes, desde su origen hasta su destino? De nuevo aparecen patrones, como el Filtro de Mensajes, que permite clasificar los mensajes de un canal, o el Ruteador Dinámico, que establece a qué destino se envía un mensaje, en base a condiciones de la red (por ejemplo, para implementar balanceo de carga en los servidores destinos).

Es un tema apasionante, que esperamos tratar en próximos artículos. En el ámbito local, Lagash, y Microsoft Consulting de Argentina, han desarrollado, en base a estos patrones, el MBI (Microsoft Business Integrator).

Patrones en Capas, Conclusión

Cuando desarrollamos aplicaciones distribuidas (o aunque no lo sean, cuando separamos la lógica en capas), podemos aplicar tanto los patrones de diseño como de arquitectura, en múltiples ocasiones. Es probable, que ya estemos aplicando alguno de los mencionados. Por ejemplo, es común, al implementar una capa de abstracción de datos, encapsular los cambios de la base SQL adoptada, en clases factoría, que se encargan de establecer la conexión con el servidor de datos. En el código completo del artículo, encontraremos ejemplos de este tipo.

En la capa de negocios, donde el cambio puede afectar más a los demás elementos del sistema, podemos adoptar patrones de conducta, como el Strategy o el Decorator, para poder ada ptarnos a las modificaciones de las reglas de proceso.

Y cuando interviene la capa de presentación, la conocida separación entre Modelo y Vista, se puede aplicar. De esta forma, el Modelo, podemos reusarlo desde distintas vistas, ya sea un formulario Windows, o una página Web.

Esperamos en próximos artículos, encarar temas como:
- Diseño de una capa de abstracción de datos
- Separación del Modelo de la Vista, para construir una aplicación con distintas interfaces
- Aplicación de patrones de integración, para comunicar aplicaciones disímiles

Como vemos, el tema patrones inunda todas las etapas del análisis, diseño y desarrollo. Es inteligente, al armar una solución, aprovechar lo ya probado.

Enlaces

http://www.microsoft.com/patterns
http://msdn.microsoft.com/practices
Las páginas de Microsoft, donde se describen los patrones, el marco que plantea Microsoft de clasificación, y ejemplos de su uso.

http://www.dofactory.com
Un catálogo con los patrones del libro de "GoF", con implementaciones de los 23 patrones, en C#

http://www.integrationpatterns.com
Excelente colección de patrones de integración.

http://www.martinfowler.com
El sitio de Martín Fowler, con información sobre patrones, metodologías y desarrollo orientado a objetos.

http://patterndigest.com/
Descripción de patrones, y novedades, noticias y foros del tema.

http://c2.com/ppr/index.html
Portland Pattern Repository, páginas sobre patrones en general.

http://hillside.net/patterns/
Patterns Home Page, desde hace años dedicados a las mejores prácticas del uso de patrones

http://www.cs.wustl.edu/~schmidt/patterns.html
Design Patterns, Pattern Languages, and Frameworks, la página de Douglas Schmidt sobre patrones y lenguajes de patrones.

Lecturas

Design Patterns, Addison Wesley, de Gamma, Helm, Johnson, Vlissides, el libro de base sobre los patrones de diseño.

Profesional Design Patterns in VB.NET: Building Adaptable Applications, Wrox, Fischer, Slater, Stromquist, Wu, aplicando los patrones de Gamma en .NET

UML Distilled, Addison-Wesley, Martín Fowler, un resumen sobre UML, contiene una introducción a los patrones.

Comentarios:
Sobre el articulo Realizado por Nancy el Sunday, May 09, 2004
Esta buenazo!!!

Gracias mil
Nancy

Responder este comentario
Biento! Realizado por chavie el Friday, April 08, 2005
Muy buen articulo, concreto, nada de chamuyo que termina aburriendo.

Responder este comentario
Opinion Articulo Realizado por christianpm el Tuesday, December 27, 2005
Esta muy bueno el articulo muy concreto y cubre muchos patrones de diseño
Responder este comentario
Muy bueno. Realizado por jochercoles el Wednesday, December 28, 2005
Yo hice un curso de cuatro clases en una intitución muy conocida y no entendi nada, lo que vi aca me gusto y me parecio muy entendible.
Responder este comentario
Agregar comentarios
ISOFTLAND software corporativo