|
|
| Enero 2003
|
Patterns en .NET
Tema: .NET Nivel: |
Angel
"Java" López |
El desarrollo de software es una actividad humana compleja.
Otras ciencias o artes, no abarcan tantos niveles distintos de
detalle, como la creación de programas. Actualmente, con el
nivel de exigencia de los usuarios, y la plétora de
tecnologías disponibles, cada sistema, pequeño o grande, nos
demanda una cantidad de esfuerzo, que es necesario apelar a
cada herramienta y habilidad, para obtener un mejor resultado.
Si ha estado en este trabajo un tiempo, habrá aprendido a
reutilizar su código, y tendrá su marco de trabajo básico para
usar de base para nuevos proyectos. No es el único. A lo largo
de la historia de la programación, han aparecido
recomendaciones y metodologías, para llevar a buen puerto el
análisis, diseño e implementación de sistemas. Ya podemos
recordar la programación estructurada, y la más "nueva"
orientación a objetos.
Una de esas corrientes, es el uso de patrones. Estudiemos
en este artículo, que es un patrón, y cómo se aplica en
particular en la nueva tecnología .NET.
Una breve historia
Es curioso que el concepto de patrón haya aparecido en la
arquitectura (la de construcción de edificios). Fue el
arquitecto Christopher Alexander quien estudió la idea de
patrón, en el contexto de construcción de edificios y
comunidades. Él escribió, ya en 1977:
| Cada patrón 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 se refería a la aplicaciones de patrones en
arquitectura, pero notamos que se puede aplicar perfectamente
a la ingeniería de software. Podemos usar objetos y clases, en
lugar de paredes, espacios y edificios, pero la idea básica es
la misma.
A fines de los ochenta, esta idea de patrones de software,
fue tomando forma. El término "software architecture" comenzó
a popularizarse. En conferencias y reuniones, los
especialistas del tema fueron incubando la idea de un manual
para arquitectos de sistemas, una especie de guía de mejores
prácticas, que ya se habían comenzado a utilizar.
Ken Beck, de la comunidad de Smalltalk, el ambiente de
objetos, difundió las ideas de Alexander, adaptándolas a la
arquitectura de sistemas, desde una columna de "Smalltalker
Report". Peter Coad coleccionaba soluciones ya encontradas a
problemas de diseño, como son los patrones, como menciona en
un artículo suyo de 1992, publicado en las comunicaciones de
la ACM.
Pero es con el libro de Gamma, Helm, Johnson y Vlissides,
el "Gang of Four", titulado "Design Patterns" (Patrones de
Diseño), con el que aparece con fuerza el concepto. Catalogan
una serie de patrones de diseño, que hasta hoy son la base de
otras clasificaciones. Ese libro se ha convertido en casi un
objeto de culto, y es la referencia obligada del tema que nos
ocupa.
¿Qué es un Design Pattern?
Pero basta ya de introducción a la
historia, y definamos qué es un patrón de diseño (hay otros
tipos de patrones, como los de arquitectura, y de
integración).
Lo fundamental, que es una
SOLUCION a un PROBLEMA. Y que esa solución encontrada, ya ha
sido usada en varios proyectos reales. Y no es entonces un
trozo de código, o una librería, o un marco de trabajo: es una
descripción de una solución, cuya implementación puede variar
de entorno a entorno, o dependiendo del lenguaje de
implementación o tecnología. Se describe entonces con:
- El nombre: Todo patrón, para ser referido en
otros estudios, tiene un nombre. A veces, la elección de
este nombre no ha sido fácil. Sucede con los patrones
nuevos, que más de un grupo lo bautiza de distinta forma.
Pero con el tiempo, uno de los nombres designados triunfa
entre la comunidad.
- El problema: Describe el problema original a
solucionar. Puede incluir desde detalles específicos, aunque
se prefiere una descripción general que pueda aplicarse en
varios contextos.
- La solución: Como mencionamos, éste es el
elemento importante del patrón. Enuncia un esquema de
solución al problema, que puede implementarse de distintas
formas.
- Las consecuencias: En todo problema y solución,
se presentan distintas fuerzas. Cada solución tiene sus pro
y sus contra. A veces, para el mismo problema, hay más de un
patrón aplicable.
Tenemos que destacar que en cada patrón, hay entonces un
problema y una solución. Y un patrón no es adoptado por la
comunidad, y no merece ese nombre, hasta que no es aplicado
exitosamente en sistemas en funcionamiento. No se aceptan
patrones teóricos: cada uno debe estar respaldado por casos de
éxito reales. 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.
Clasificación de Patrones
Gamma y sus colaboradores se concentran en los patrones de
diseño y los clasifican en las siguientes categorías.
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.
Es un ejemplo del patrón Abstract Factory, que nos da una
interface para crear objetos de alguna familia, sin
especificar la clase en concreto.
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.
Otro de los clásicos, es el Fachada o Facade, que provee
una interface unificada a un conjunto de funciones del
sistema.
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.
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
Describamos un caso de patrón,
como se estila en la literatura.
Contexto:
Necesitamos que alguna funcionalidad se acceda desde el
resto del sistema. Y es preciso que esos datos sean únicos: un
solo objeto o instancia que presente esa funcionalidad. Por
ejemplo, un objeto que sea el que se comunique con el Sistema
Operativo, para lanzar procesos. O un objeto que presente las
funciones necesarias para manejar un Sistema Contable, y que
sea el punto de entrada a un sistema externo al nuestro.
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:
Figura 1: Diagrama UML
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 Constructor
Private Sub New()
mTime = Now.ToLongTimeString
MsgBox("New Singleton Object")
End Sub
Public Shared Function GetInstance() As Singleton
If mInstance Is Nothing Then
mInstance = New Singleton()
End If
Return mInstance
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 Constructor
Private Sub New()
mTime = Now.ToLongTimeString
MsgBox("New Singleton Object")
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
End Class
Veamos otra implementación, esta vez en C#.
using System;
public class Singleton
{
private static Singleton instance;
private Singleton() {}
public static Singleton Instance
{
get
{
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 Singleton
{
private static readonly Singleton instance = new Singleton();
private Singleton(){}
public static Singleton Instance
{
get
{
return instance;
}
}
}
Demos ahora un ejemplo, de un patrón, usado en un ejemplo
de la propia empresa de Redmond.
|
Figura 2: Sistema
original
| El patrón Fachada
Este un patrón que Microsoft recomienda de alguna forma en
sus guías de arquitectura, y sus ejemplos. En qué consiste?
Consideremos un sistema que tenga una capa de presentación
(formularios Windows o páginas ASP.NET), y necesite
comunicarse con clases de la capa de negocios.
Notamos a simple vista, que hay mucha interacción entre los
objetos de las dos capas. La comunicación, con el tiempo, se
puede ir complicando. Y cualquier cambio en los objetos de la
capa de negocios, puede afectar a varios métodos de la capa de
presentación.
En nuestro auxilio acude el patrón de Fachada. Consiste en
construir una clase que se interponga entre las clases
clientes y las clases de servicios, como se muestra en el
esquema.
Figura 3: Usando el
Patrón
Y es justamente, es la solución
adoptada en varios ejemplos de Microsoft, como el nuevo
Duwamish 7.
Fachada en Duwamish
El Duwamish 7 implementa un sitio
web, con ASP.NET, con consultas de un catálogo de libros, un
carrito de compras, la toma del pedido, y los datos del
cliente.
El
código fuente esta disponible en el sitio de Microsoft (ver
referencias) o viene incluido con el Visual Studio .NET.
Si abrimos la solución en el
Visual Studio.NET, encontramos la estructura:
Vemos que hay varios proyectos. ¿Y
dónde está aplicado entonces el patrón que tenemos entre
manos?
Pues en el primer proyecto (BusinessFacade) encontraremos
que los autores del ejemplo usaron el patrón de Fachada.
No se usó una sola clase, sino que cada subsistema
(Clientes, Ordenes de Pedido, Productos) tiene una propia.
Examinemos un resumen del código del sistema de Clientes: Namespace Duwamish7.BusinessFacade
Public Class CustomerSystem
Inherits MarshalByRefObject
Public Function GetCustomerByEmail( _
ByVal emailAddress As String, _
ByVal password As String) _
As CustomerData
'
' Obtiene los datos de un cliente
'
End Function
Public Function UpdateCustomer( _
ByVal customer as CustomerData) _
As Boolean
'
' Actualiza un cliente
'
End Function
Public Function CreateCustomer( _
ByVal emailAddress As String, _
ByVal password As String, _
ByVal name As String, _
ByVal address As String, _
ByVal country As String, _
ByVal phoneNumber As String, _
ByVal fax As String, _
ByRef custData As CustomerData) As Boolean
'
' Crea un nuevo cliente
'
End Function
End Class
End Namespace
Esta es la funcionalidad que la capa de presentación
necesita: obtener los datos de un cliente, dado su email, o
actualizar los datos de un cliente. Los objetos de la capa
cliente, solamente necesitan conocer esta interface de
servicio, esta clase que implementa el patrón Fachada. Cuando
cambie la forma de implementar la actualización de un cliente,
ya sea porque cambie la base de datos, o los procesos de
validación de datos, todos esos cambios quedan encapsulados,
ocultos, debajo de la fachada, resguardando a la presentación
de esas mutaciones.
Conclusión
El tema patrones se usa desde el siglo pasado, en el
desarrollo de software. Y con el nuevo .NET, la llegada a la
madurez de la tecnología Microsoft (al fin herencia en todo,
interfaces, clase, objetos, y una librería de clases base
impresionante), y la necesidad de construir aplicaciones más
complejas, se impone el estudio del tema. Recomiendo revisar
los documentos de Microsoft, y de otras tecnologías, así como
aprender de los ejemplos. Espero que encuentren, como yo,
placer en su estudio, y utilidad en su aplicación.
Referencias
- Todo sobre
patrones, según Microsoft
- Artículos y
recursos sobre arquitectura de aplicaciones
- Enterprise
Solution Patterns Using Microsoft .NET
- Ejemplos
de aplicaciones distribuidas, con código
completo.
Aquí encontraremos el Duwamish 7, el
ColdStorage, el PetShop y otros.
- Explicación
del uso del patrón en otra tecnología: Java.
- Building
Distributed Applications,
las recomendaciones de
Microsoft a aplicar en la construcción de este tipo de
aplicaciones.
- Un catálogo con los
patrones del libro de "GoF", con implementaciones de los
23 patrones, en C#
- Descripción de
patrones, y novedades, noticias y foros del tema.
- Portland Pattern
Repository, páginas sobre patrones en general.
- Patterns Home
Page, desde hace años dedicados a las mejores prácticas
del uso de patrones
- Excelente
colección de patrones de integración.
- El sitio de
Martín Fowler, con información sobre patrones,
metodologías y desarrollo orientado a objetos.
Angel "Java" López (Buenos Aires - Argentina) es
Microsoft MVP (Most Valuable Professional). Posee más de
veinte años de experiencia en el diseño y desarrollo de
software trabajando en diferentes plataformas y lenguajes. Se
especializa en desarrollo de intranets y de sitios web,
empleando distintas tecnologías. Actualmente se desempeña como
Líder de la Comunidad de desarrolladores J# del Grupo de
Usuarios Microsoft, donde dicta cursos y jornadas
periodicamente. Trabaja también como docente de programación
en Java y .NET. Puede encontrarlo en http://www.ajlopez.com/.
|