<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type='text/xsl' href='http://lucasontivero.spaces.live.com/mmm2008-07-24_12.50/rsspretty.aspx?rssquery=en-US;http%3a%2f%2flucasontivero.spaces.live.com%2fcategory%2fPatterns%2ffeed.rss' version='1.0'?><rss version="2.0" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:msn="http://schemas.microsoft.com/msn/spaces/2005/rss" xmlns:live="http://schemas.microsoft.com/live/spaces/2006/rss" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:cf="http://www.microsoft.com/schemas/rss/core/2005" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Lucas Ontivero: Patterns</title><description /><link>http://lucasontivero.spaces.live.com/?_c11_BlogPart_BlogPart=blogview&amp;_c=BlogPart&amp;partqs=catPatterns</link><language>en-US</language><pubDate>Fri, 15 Aug 2008 15:15:42 GMT</pubDate><lastBuildDate>Fri, 15 Aug 2008 15:15:42 GMT</lastBuildDate><generator>Microsoft Spaces v1.1</generator><docs>http://www.rssboard.org/rss-specification</docs><ttl>60</ttl><cf:parentRSS>http://lucasontivero.spaces.live.com/blog/feed.rss</cf:parentRSS><live:type>blogcategory</live:type><live:identity><live:id>3988747590285877710</live:id><live:alias>lucasontivero</live:alias></live:identity><cf:listinfo><cf:group ns="http://schemas.microsoft.com/live/spaces/2006/rss" element="typelabel" label="Type" /><cf:group ns="http://schemas.microsoft.com/live/spaces/2006/rss" element="tag" label="Tag" /><cf:group element="category" label="Category" /><cf:sort element="pubDate" label="Date" data-type="date" default="true" /><cf:sort element="title" label="Title" data-type="string" /><cf:sort ns="http://purl.org/rss/1.0/modules/slash/" element="comments" label="Comments" data-type="number" /></cf:listinfo><item><title>[Patterns] UnitOfWork</title><link>http://lucasontivero.spaces.live.com/Blog/cns!375AE0CCD1AF61CE!456.entry</link><description>&lt;div align=justify&gt;&lt;a href="http://www.google.com/translate?u=http://lucasontivero.spaces.live.com/blog/cns!375AE0CCD1AF61CE!456.entry&amp;amp;langpair=es|en&amp;amp;hl=en&amp;amp;ie=UTF8" target="_blank"&gt;[Translate this post to english with google]&lt;/a&gt;&lt;/div&gt;
&lt;div align=justify&gt; &lt;/div&gt;
&lt;div align=justify&gt;Este es uno de los patrones más útiles (desde mi punto de vista) con que me he encontrado en el libro &amp;quot;&lt;a href="http://martinfowler.com/books.html#eaa"&gt;Patterns of Enterprise Application Architecture&lt;/a&gt;&amp;quot; (P of EAA) de Martin Fowler. Como dice Martin en su libro &lt;a href="http://martinfowler.com/eaaCatalog/unitOfWork.html"&gt;este patrón:&lt;/a&gt;&lt;/div&gt;
&lt;div align=center&gt;&amp;quot;Maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems.&amp;quot;&lt;/div&gt;
&lt;div align=justify&gt;&lt;/div&gt;
&lt;div align=justify&gt;&lt;a href="http://martinfowler.com/eaaCatalog/unitOfWorkInterface.gif"&gt;&lt;img style="display:block;margin:0px auto 10px;width:160px;cursor:hand;text-align:center" alt="" src="http://martinfowler.com/eaaCatalog/unitOfWorkInterface.gif" border=0&gt;&lt;/a&gt; Este patrón se utiliza entonces para trabajar con un conjunto de objetos persistentes que deben tratarse como una &amp;quot;unidad&amp;quot; de trabajo, almacenandose en una base de datos de manera atómica. Este patrón es el encargado de trackear todos aquellos objetos que son nuevos, y que por lo tanto deben persistirse, todos los objetos que han sido modificados y que deben actualizarse en la DB y todos los que han sido borrados y deben quitarse de la base de datos.&lt;/div&gt;
&lt;div align=justify&gt;&lt;/div&gt;
&lt;div align=justify&gt;Mediante la implementación del patrón UnitOfWork, se logra una disminución de la cantidad de idas y vueltas hacia la base de datos ya que los cambios se realizan por lotes (o unidades de trabajo) redundando en una mejora de la performance del sistema porque muchas veces el cuello de botella de las aplicaciones se encuentra en la red de datos. Otro aspecto interesante es que posibilita el esquema de trabajo desconectado con bloqueos optimistas sobre la base de datos, es decir, no se mantienen bloqueados los registros por largos períodos de tiempo sino que se abre una conexión, se inicia una transacción, se hacen los cambios, se commitea y se libera la conexión todo esto en muy pero muy poco tiempo. &lt;/div&gt;
&lt;div align=justify&gt;&lt;/div&gt;
&lt;div align=justify&gt;De ser necesaria la incorporación de un control de concurrencia sobre los registros que serán afectados durante la transación, de modo de mantener la consistencia de los datos, este patrón nos brinda el ámbito adecuado en donde implementarlo. &lt;/div&gt;
&lt;div align=justify&gt;Veamos un caso concreto, el famoso ejemplo de la factura. Existe una factura que el usuario debe modificar, entonces traemos desde la base de datos la factura con sus items (de factura) cargados, luego, una vez que lo presentamos en pantalla, el usuario hace lo siguiente:&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;div align=justify&gt;Agrega dos items más a la lista de items,&lt;/div&gt;
&lt;li&gt;
&lt;div align=justify&gt;Modifica el importe y/o la cantidad de productos de uno de los items y finalmente,&lt;/div&gt;
&lt;li&gt;
&lt;div align=justify&gt;Elimina uno de los item.&lt;/div&gt;&lt;/ul&gt;
&lt;p align=justify&gt;En este caso, cuando deben persistirse los datos? apenas agrega, modifica o elimina un item? o debe tratarse a la factura como una unidad y persistir todo junto? Si algo falla,... debe guardarse el resto? que sucede si otro usuario (además del que estamos hablando) estaba trabajando con el mismo documento al mismo tiempo pero guardó primero? como sabemos que fue lo que modificó el usuario y que, por lo tanto, debemos guardar? guardamos primero la factura y luego los items o al revés? 
&lt;p align=justify&gt;Todas las respuestas a estas preguntas (que considero que las fuiste contestando) se resuelven mediante la implementación de este patrón. 
&lt;p align=justify&gt;Voy a explicarlo un poco. El Unit Of Work, como se observa en la figura de arriba, se implementa mediante una única clase la cual tendrá al menos tres listas, una lista para los objetos nuevos que deben guardarse en la db, otra lista para los objetos que han sido modificados y que por lo tanto deben modificarse en la db y, otra lista para los objetos que deben eliminarse. Opcionalmente, o mejor dicho, según la implementación lo requiera, puede contener una cuarta lista para almacenar clones de los objetos que se traen desde la base de datos, de manera que antes de persistir un objeto pueda corroborar, mediante estos clones de los objetos originales, que los registros correspondientes no han sido modificados por otro usuario. 
&lt;p align=justify&gt;Una razón para leer el libro y no solo conformarse con este artículo es que Fowler hace un análisi exaustivo de este patrón (y de todos sus patrones), sus formas de implementar, cuando implementarlos, pros y contras y sobre todo, lo que a mi más me gustó fueron los distintos intentos por hacer esta clase lo más transparente posible para el programador. Así, por ejemplo, analiza la posibilidad de que todas las clases persistibles hereden de una clase base que automáticamente las registre como nuevas en el contenedor, que cuando se invoque el setter methos de una propiedad, esta notifique al UnitOfWork correspondiente para que la registre como dirty, etc. Personalmente estube probando esto y otras ideas como AOP, que no me convenció para nada, y extensions methods con los cuales le agrega m'etodos de persistencia a los objetos que heredaban de esa clase base. 
&lt;p align=justify&gt;En cuanto a AOP, no me convención porque las opciones eran todas muy feas, o usaba el .Net Profiling API con C++ para capturar la ejecución del JIT y entonces inyectarle código MSIL a los setters, o las clases heredaban de ContextBoundObject para, mediante los proxies de remounting, poder interceptar las invocaciones a las propiedades (lento, sucio, que más?) o, usando un compilador de terceros (no MS) casi en todos los casos en beta 0.000001. Así que definitivamente por el momento no lo ví como una opción. 
&lt;p align=justify&gt;En resumen, creo que es mejor, aunque un poquito mas tedioso y propenso a errores, dejar que sea el programador quien registre los objetos en el Unit of Work. 
&lt;p align=justify&gt;Acá dejo una implementación sencillísima de UnitOfWork sin control de concurrencias y en colaboración con un DataMapper trivial. Más abajo les dejo un proyecto que implementa esta clase. 
&lt;div style="height:400px"&gt;&lt;pre style="border-right:#eee 1px solid;padding-right:5px;border-top:#eee 1px solid;padding-left:5px;border-bottom-width:1px;overflow:auto;border-left:#eee 1px solid;width:95%;padding-top:5px;height:100%"&gt;&lt;span style="color:blue"&gt;using&lt;/span&gt; System;

&lt;span style="color:blue"&gt;using&lt;/span&gt; System.Collections.Generic;
&lt;span style="color:blue"&gt;using&lt;/span&gt; System.Text;
&lt;span style="color:blue"&gt;using&lt;/span&gt; System.Transactions;
&lt;span style="color:blue"&gt;using&lt;/span&gt; System.Data.SqlClient;
&lt;span style="color:blue"&gt;using&lt;/span&gt; System.Configuration;
&lt;span style="color:blue"&gt;using&lt;/span&gt; System.Threading;
&lt;span style="color:blue"&gt;using&lt;/span&gt; System.Resources;

&lt;span style="color:blue"&gt;namespace&lt;/span&gt; Patterns
{
        &lt;span style="color:green"&gt;// Nuestra clase UnitOfWork (Martin Fowler)&lt;/span&gt;
        &lt;span style="color:blue"&gt;public&lt;/span&gt; &lt;span style="color:blue"&gt;class&lt;/span&gt; UnitOfWork
        {
                &lt;span style="color:green"&gt;// Aquí estan las tres listas de las que hablamos&lt;/span&gt;
                &lt;span style="color:green"&gt;// Ademas de estas puede existir una cuarta que almacene&lt;/span&gt;
                &lt;span style="color:green"&gt;// los objetos limpios (o que se leyeron de la db)&lt;/span&gt;
                List&amp;lt;IBusinessObject&amp;gt; newObjects;
                List&amp;lt;IBusinessObject&amp;gt; dirtyObjects;
                List&amp;lt;IBusinessObject&amp;gt; removedObjects;

                &lt;span style="color:green"&gt;// Creamos las listas en este constructor&lt;/span&gt;
                &lt;span style="color:blue"&gt;public&lt;/span&gt; UnitOfWork()
                {
                        newObjects = &lt;span style="color:blue"&gt;new&lt;/span&gt; List&amp;lt;IBusinessObject&amp;gt;();
                        dirtyObjects = &lt;span style="color:blue"&gt;new&lt;/span&gt; List&amp;lt;IBusinessObject&amp;gt;();
                        removedObjects = &lt;span style="color:blue"&gt;new&lt;/span&gt; List&amp;lt;IBusinessObject&amp;gt;();
                }

                &lt;span style="color:blue"&gt;public&lt;/span&gt; &lt;span style="color:blue"&gt;void&lt;/span&gt; New(IBusinessObject bo)
                {
                        Guard.NotNull(Resources.parameter_is_null, &amp;quot;&lt;span style="color:magenta"&gt;bo&lt;/span&gt;&amp;quot;, bo);
                        Guard.IsTrue (Resources.object_is_dirty, dirtyObjects.Contains(bo));
                        Guard.IsTrue (Resources.object_is_deleted, removedObjects.Contains(bo));
                        Guard.IsTrue(Resources.object_is_already_inserted, newObjects.Contains(bo));

                        newObjects.Add(bo);
                }

                &lt;span style="color:blue"&gt;public&lt;/span&gt; &lt;span style="color:blue"&gt;void&lt;/span&gt; Remove(IBusinessObject bo)
                {
                        Guard.NotNull(Resources.parameter_is_null, &amp;quot;&lt;span style="color:magenta"&gt;bo&lt;/span&gt;&amp;quot;, bo);
                        &lt;span style="color:blue"&gt;if&lt;/span&gt; (newObjects.Remove(bo)) &lt;span style="color:blue"&gt;return&lt;/span&gt;;
                        dirtyObjects.Remove(bo);

                        &lt;span style="color:blue"&gt;if&lt;/span&gt; (!removedObjects.Contains(bo))
                        removedObjects.Add(bo);
                }

                &lt;span style="color:blue"&gt;public&lt;/span&gt; &lt;span style="color:blue"&gt;void&lt;/span&gt; Update(IBusinessObject bo)
                {
                        Guard.NotNull(Resources.parameter_is_null, &amp;quot;&lt;span style="color:magenta"&gt;bo&lt;/span&gt;&amp;quot;, bo);
                        Guard.IsTrue(Resources.object_is_deleted, removedObjects.Contains(bo));

                        &lt;span style="color:blue"&gt;if&lt;/span&gt; (!newObjects.Contains(bo) &amp;amp;&amp;amp; !dirtyObjects.Contains(bo))
                        dirtyObjects.Add(bo);
                }

                &lt;span style="color:green"&gt;// El método Commit es el encargado de iniciar las transacciones,&lt;/span&gt;
                &lt;span style="color:green"&gt;// y realizar la invocación a la base de datos.&lt;/span&gt;
                &lt;span style="color:blue"&gt;public&lt;/span&gt; &lt;span style="color:blue"&gt;void&lt;/span&gt; Commit()
                {
                        &lt;span style="color:blue"&gt;string&lt;/span&gt; connectString = &lt;span style="color:blue"&gt;string&lt;/span&gt;.Empty;
                        &lt;span style="color:blue"&gt;using&lt;/span&gt; (TransactionScope transactionScope = &lt;span style="color:blue"&gt;new&lt;/span&gt; TransactionScope())
                        {
                                connectString = ConfigurationManager.ConnectionStrings[&amp;quot;&lt;span style="color:magenta"&gt;Patterns&lt;/span&gt;&amp;quot;].ConnectionString;

                                &lt;span style="color:blue"&gt;using&lt;/span&gt; (SqlConnection connection = &lt;span style="color:blue"&gt;new&lt;/span&gt; SqlConnection(connectString))
                                {
                                        &lt;span style="color:blue"&gt;try&lt;/span&gt;
                                        {
                                                &lt;span style="color:green"&gt;// Construimos las sentencias SQL para luego pasárselas a la DB&lt;/span&gt;
                                                &lt;span style="color:green"&gt;// mediante un command. Para esto, en .Net hay que hacerlo separando&lt;/span&gt;
                                                &lt;span style="color:green"&gt;// las sentencias con un punto y como (;)&lt;/span&gt;
                                                StringBuilder stringBuilder = &lt;span style="color:blue"&gt;new&lt;/span&gt; StringBuilder();

                                                &lt;span style="color:blue"&gt;foreach&lt;/span&gt; (IBusinessObject bo &lt;span style="color:blue"&gt;in&lt;/span&gt; newObjects)
                                                stringBuilder.Append(Mapper.Instance.Insert(bo) + &amp;quot;&lt;span style="color:magenta"&gt;;&lt;/span&gt;&amp;quot;);

                                                &lt;span style="color:blue"&gt;foreach&lt;/span&gt; (IBusinessObject bo &lt;span style="color:blue"&gt;in&lt;/span&gt; dirtyObjects)
                                                stringBuilder.Append(Mapper.Instance.Update(bo) + &amp;quot;&lt;span style="color:magenta"&gt;;&lt;/span&gt;&amp;quot;);

                                                &lt;span style="color:blue"&gt;foreach&lt;/span&gt; (IBusinessObject bo &lt;span style="color:blue"&gt;in&lt;/span&gt; removedObjects)
                                                stringBuilder.Append(Mapper.Instance.Delete(bo) + &amp;quot;&lt;span style="color:magenta"&gt;;&lt;/span&gt;&amp;quot;);

                                                &lt;span style="color:blue"&gt;string&lt;/span&gt; command = stringBuilder.ToString();

                                                &lt;span style="color:green"&gt;// Abre la conexió, crea el comando con las sentencias SQL&lt;/span&gt;
                                                &lt;span style="color:green"&gt;// e invoca al RDBMS.&lt;/span&gt;
                                                connection.Open();
                                                SqlCommand command1 = &lt;span style="color:blue"&gt;new&lt;/span&gt; SqlCommand(command, connection);
                                                command1.ExecuteNonQuery();

                                                &lt;span style="color:green"&gt;// Limpia las listas si todo estuvo bien.&lt;/span&gt;
                                                ClearAll();
                                        }
                                        &lt;span style="color:blue"&gt;catch&lt;/span&gt; (Exception ex)
                                        {
                                                System.Console.WriteLine(&amp;quot;&lt;span style="color:magenta"&gt;Exception Message: {0}&lt;/span&gt;&amp;quot;, ex.Message);
                                        }
                                }
                                transactionScope.Complete();
                        }
                }

                &lt;span style="color:blue"&gt;private&lt;/span&gt; &lt;span style="color:blue"&gt;void&lt;/span&gt; ClearAll()
                {
                        newObjects.Clear();
                        dirtyObjects.Clear();
                        removedObjects.Clear();
                }
        }
}

&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;El proyecto: &lt;a href="http://www.carloszanini.com.ar/shared/UnitOfWork.zip" target="_blank"&gt;http://www.carloszanini.com.ar/shared/UnitOfWork.zip&lt;/a&gt; No esperen gran cosa. Gracias a Carlos Zanini por el hosting. 
&lt;p&gt;&lt;strong&gt;Lucas Ontivero&lt;/strong&gt; 
&lt;p&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=3988747590285877710&amp;page=RSS%3a+%5bPatterns%5d+UnitOfWork&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=lucasontivero.spaces.live.com&amp;amp;GT1=lucasontivero"&gt;</description><comments>http://lucasontivero.spaces.live.com/Blog/cns!375AE0CCD1AF61CE!456.entry#comment</comments><guid isPermaLink="true">http://lucasontivero.spaces.live.com/Blog/cns!375AE0CCD1AF61CE!456.entry</guid><pubDate>Fri, 14 Sep 2007 18:42:33 GMT</pubDate><slash:comments>1</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://lucasontivero.spaces.live.com/blog/cns!375AE0CCD1AF61CE!456/comments/feed.rss</wfw:commentRss><wfw:comment>http://lucasontivero.spaces.live.com/Blog/cns!375AE0CCD1AF61CE!456.entry#comment</wfw:comment><dcterms:modified>2007-09-14T18:48:20Z</dcterms:modified></item><item><title>[Patterns] Lifetime Container Pattern</title><link>http://lucasontivero.spaces.live.com/Blog/cns!375AE0CCD1AF61CE!438.entry</link><description>&lt;div&gt;&lt;font size=2&gt;
&lt;p&gt;Muchas veces es necesario mantener el control del tiempo de vida de los objetos. En tecnologias de código administrado como .Net o Java, a diferencia de otros como C y C++, existe un mecanismo de recolección de basura que libera al programador de la tarea de destrucción de objetos y la liberación de la memoria. No obstante, existen ocaciones en las que tener el control de la destrucción de los objetos es muy conveniente. 
&lt;p&gt;Por ejemplo, cuando la creación de un objeto consume mucho tiempo y recursos del procesador, crear estos objetos y permitir que se destruyan cuando se pierden las referencia a él puede que no sea una buena idea, en este caso se opta por crear un pool de objetos que no se destruyan cuando ya no se usen sino que permanezan disponibles aún cuando no se los esté usando. Otra situación se da cuando se necesita liberar un conjunto de recursos (objetos) que ya no se van a utilizar más porque en su conjunto representan o sirven a una sola unidad de trabajo. Un caso concreto es cuando se utilizan objetos que administran gran cantidad de otros objetos también completos como los WorkItem del Composite UI Appication Block el cual mantiene colecciones de objetos Views, Controlers, Commands, EventTopics, Services, SmartParts, UIExtensionSites, WorkSpaces, otros WorkItems y algunas cosas más. En este caso, cuando se libera un workitem, se deben liberar todos los objetos que han colaborado con él. 
&lt;p&gt;El Lifetime container, como su nombre lo indica, es un contenedor (una colección) que mantiene vivas las referencias a todos los objetos que se registran en él. Vamos al código:&lt;/font&gt; &lt;/div&gt;&lt;pre style="border-right:#eee 1px solid;padding-right:5px;border-top:#eee 1px solid;padding-left:5px;font-size:12px;padding-bottom:20px;overflow:auto;border-left:#eee 1px solid;width:95%;padding-top:5px;border-bottom:#eee 1px solid;font-family:courier new;height:300px;background-color:#fff"&gt;&lt;font color=blue&gt;using&lt;/font&gt; System;
&lt;font color=blue&gt;using&lt;/font&gt; System.Collections;
&lt;font color=blue&gt;using&lt;/font&gt; System.Collections.Generic;

&lt;font color=blue&gt;namespace&lt;/font&gt; Temosoft.Containers
{
        &lt;font color=blue&gt;public&lt;/font&gt; &lt;font color=blue&gt;class&lt;/font&gt; LifetimeContainer : IEnumerable&amp;lt;&lt;font color=blue&gt;object&lt;/font&gt;&amp;gt;, IDisposable
        {
                &lt;font color=blue&gt;#region&lt;/font&gt; Private Fields
                &lt;font color=green&gt;// El contenedor interno que mantiene vivas las referencias.&lt;/font&gt;
                &lt;font color=blue&gt;private&lt;/font&gt; List&amp;lt;&lt;font color=blue&gt;object&lt;/font&gt;&amp;gt; items = &lt;font color=blue&gt;new&lt;/font&gt; List&amp;lt;&lt;font color=blue&gt;object&lt;/font&gt;&amp;gt;();
                &lt;font color=blue&gt;#endregion&lt;/font&gt;

                &lt;font color=blue&gt;#region&lt;/font&gt; Public Methods (Operations)
                &lt;font color=blue&gt;public&lt;/font&gt; &lt;font color=blue&gt;void&lt;/font&gt; Add(&lt;font color=blue&gt;object&lt;/font&gt; item)
                {
                        items.Add(item);
                }

                &lt;font color=blue&gt;public&lt;/font&gt; &lt;font color=blue&gt;void&lt;/font&gt; Remove(&lt;font color=blue&gt;object&lt;/font&gt; item)
                {
                        &lt;font color=blue&gt;if&lt;/font&gt; (!items.Contains(item))
                        &lt;font color=blue&gt;return&lt;/font&gt;;

                        items.Remove(item);
                }

                &lt;font color=blue&gt;public&lt;/font&gt; &lt;font color=blue&gt;bool&lt;/font&gt; Contains(&lt;font color=blue&gt;object&lt;/font&gt; item)
                {
                        &lt;font color=blue&gt;return&lt;/font&gt; items.Contains(item);
                }
                &lt;font color=blue&gt;#endregion&lt;/font&gt;

                &lt;font color=blue&gt;#region&lt;/font&gt; Public Properties (Read only)
                &lt;font color=blue&gt;public&lt;/font&gt; &lt;font color=blue&gt;int&lt;/font&gt; Count
                {
                        get { &lt;font color=blue&gt;return&lt;/font&gt; items.Count; }
                }
                &lt;font color=blue&gt;#endregion&lt;/font&gt;


                &lt;font color=blue&gt;#region&lt;/font&gt; IDisposable &lt;font color=blue&gt;interface&lt;/font&gt;
                &lt;font color=blue&gt;public&lt;/font&gt; &lt;font color=blue&gt;void&lt;/font&gt; Dispose()
                {
                        Dispose(&lt;font color=blue&gt;true&lt;/font&gt;);
                }

                &lt;font color=blue&gt;protected&lt;/font&gt; &lt;font color=blue&gt;void&lt;/font&gt; Dispose(&lt;font color=blue&gt;bool&lt;/font&gt; disposing)
                {
                        &lt;font color=blue&gt;if&lt;/font&gt; (disposing)
                        {
                                List&amp;lt;&lt;font color=blue&gt;object&lt;/font&gt;&amp;gt; itemsCopy = &lt;font color=blue&gt;new&lt;/font&gt; List&amp;lt;&lt;font color=blue&gt;object&lt;/font&gt;&amp;gt;(items);
                                itemsCopy.Reverse();

                                &lt;font color=blue&gt;foreach&lt;/font&gt; (&lt;font color=blue&gt;object&lt;/font&gt; o &lt;font color=blue&gt;in&lt;/font&gt; itemsCopy)
                                {
                                        IDisposable d = o &lt;font color=blue&gt;as&lt;/font&gt; IDisposable;

                                        &lt;font color=blue&gt;if&lt;/font&gt; (d != &lt;font color=blue&gt;null&lt;/font&gt;)
                                        d.Dispose();
                                }

                                items.Clear();
                        }
                }
                &lt;font color=blue&gt;#endregion&lt;/font&gt;


                &lt;font color=blue&gt;#region&lt;/font&gt; Enumerators
                &lt;font color=blue&gt;public&lt;/font&gt; IEnumerator&amp;lt;&lt;font color=blue&gt;object&lt;/font&gt;&amp;gt; GetEnumerator()
                {
                        &lt;font color=blue&gt;return&lt;/font&gt; items.GetEnumerator();
                }

                IEnumerator IEnumerable.GetEnumerator()
                {
                        &lt;font color=blue&gt;return&lt;/font&gt; GetEnumerator();
                }
                &lt;font color=blue&gt;#endregion&lt;/font&gt;
        }
}&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Como se puede ver, esta clase es muy parecida a una colección salvo porque implementa IDisposable para manejar la liberación de los objetos en orden inverso a su registración. No implementa ICollection porque en este caso no se debe posibilitar el método CopyTo() y porque en este caso, por razones de sencillez, no se hizo thread safe.&lt;/em&gt; 
&lt;p&gt;Como se ve, este es un contenedor sumamente sencillo y surge la pregunta &amp;quot;que hay de nuevo acá?&amp;quot;, bueno, la verdad es que lo nuevo lo encontramos en la manera o las formas de usarlo. Veamos, en la entrada de este blogs: &lt;a href="http://lucasontivero.spaces.live.com/blog/cns!375AE0CCD1AF61CE!430.entry" target="_blank"&gt;[Patterns] Distributed Applications using FactoryMethod and ServiceLocator Patterns&lt;/a&gt;, vimos como la clase ServiceLocator mantenia un diccionario de strings y objetos (después lo hicimos mediante object-object), este diccionario impide que los servicios que no se utilizan puedan ser eliminados! Como podemos manejar esto con un LifetimeContainer? la respuesta es NO mantener las referencias. Esto lo podemos hacer implementando el ServiceLocator mediante un weakRefDictionary&amp;lt;object, object&amp;gt; en lugar de un Dictionary&amp;lt;object, object&amp;gt;.&lt;pre style="border-right:#eee 1px solid;padding-right:5px;border-top:#eee 1px solid;overflow-y:hidden;padding-left:5px;font-size:12px;padding-bottom:20px;overflow:auto;border-left:#eee 1px solid;width:95%;padding-top:5px;border-bottom:#eee 1px solid;font-family:courier new;background-color:#fff"&gt;&lt;font color=blue&gt;public&lt;/font&gt; &lt;font color=blue&gt;class&lt;/font&gt; ServiceLocator
{
        &lt;font color=blue&gt;private&lt;/font&gt; WeakRefDictionary&amp;lt;&lt;font color=blue&gt;object&lt;/font&gt;, &lt;font color=blue&gt;object&lt;/font&gt;&amp;gt; services = &lt;font color=blue&gt;new&lt;/font&gt; WeakRefDictionary&amp;lt;&lt;font color=blue&gt;object&lt;/font&gt;, &lt;font color=blue&gt;object&lt;/font&gt;&amp;gt;();

        &lt;font color=blue&gt;public&lt;/font&gt; &lt;font color=blue&gt;void&lt;/font&gt; AddService(&lt;font color=blue&gt;object&lt;/font&gt; serviceKey, &lt;font color=blue&gt;object&lt;/font&gt; service)
&lt;/pre&gt;
&lt;p&gt;Que beneficios nos trae esto? Ahora, cada componente, plugin, unit of work, form, o lo que sea puede registrar sus servicios, de manera que estén disponibles para todas los demas componentes, mientras dure su vida y que dejen de estarlo cuando ellos son destruidos (a menos que alguien los esté usando). Por lo tanto, cada componente tiene su propio Lifetime container para manejar el ciclo de vida de SUS objetos.
&lt;p&gt;&lt;strong&gt;Lucas Ontivero&lt;/strong&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=3988747590285877710&amp;page=RSS%3a+%5bPatterns%5d+Lifetime+Container+Pattern&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=lucasontivero.spaces.live.com&amp;amp;GT1=lucasontivero"&gt;</description><comments>http://lucasontivero.spaces.live.com/Blog/cns!375AE0CCD1AF61CE!438.entry#comment</comments><guid isPermaLink="true">http://lucasontivero.spaces.live.com/Blog/cns!375AE0CCD1AF61CE!438.entry</guid><pubDate>Tue, 04 Sep 2007 15:52:20 GMT</pubDate><slash:comments>2</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://lucasontivero.spaces.live.com/blog/cns!375AE0CCD1AF61CE!438/comments/feed.rss</wfw:commentRss><wfw:comment>http://lucasontivero.spaces.live.com/Blog/cns!375AE0CCD1AF61CE!438.entry#comment</wfw:comment><dcterms:modified>2007-09-04T15:52:20Z</dcterms:modified></item><item><title>[Patterns] Distributed Applications using Facade Pattern</title><link>http://lucasontivero.spaces.live.com/Blog/cns!375AE0CCD1AF61CE!431.entry</link><description>&lt;p&gt;Este patrón tan sencillo es seguramente uno de los más importantes en el desarrollo de aplicaciones que publican sus servicios mediante Web Services. El motivo de este post es ayudar a entender la forma correcta de implementar Web Services con .Net. 
&lt;h2&gt;El problema&lt;/h2&gt;
&lt;p&gt;Afortunadamente hoy contamos con muchas herramientas y facilidades para la creación y publicación de servicios web. En .Net, es increiblemente facil crear un servicio web a partir de una clase, solo hay que extender nuestra clase de la clase System.Web.Services.WeServices y adornar el o los metodos que queremos publicar con [WebMethod] y listo. Por ejemplo:&lt;pre style="border-right:#eee 1px solid;padding-right:5px;border-top:#eee 1px solid;overflow-y:hidden;padding-left:5px;font-size:12px;padding-bottom:20px;overflow:auto;border-left:#eee 1px solid;width:500px;padding-top:5px;border-bottom:#eee 1px solid;font-family:courier new;background-color:#fff"&gt;&lt;font color=blue&gt;using&lt;/font&gt; System;
&lt;font color=blue&gt;using&lt;/font&gt; System.Web.Services;

&lt;font color=blue&gt;public&lt;/font&gt; &lt;font color=blue&gt;class&lt;/font&gt; HelloWorld: WebService {
        [WebMethod(Description=&amp;quot;&lt;font color=magenta&gt;Returns Hello&lt;/font&gt;&amp;quot;, EnableSession=&lt;font color=blue&gt;false&lt;/font&gt;)]
        &lt;font color=blue&gt;public&lt;/font&gt; &lt;font color=blue&gt;string&lt;/font&gt; Say() {
                &lt;font color=blue&gt;return&lt;/font&gt; &amp;quot;&lt;font color=magenta&gt;Hello&lt;/font&gt;&amp;quot;;
        }
}&lt;/pre&gt;
&lt;p&gt;El problema con estas facilidades es que muchos desarrolladores entienden que el objetivo de esto es exponer en el cliente, proxies mediantes, los objetos de negocios que se encuentra en el servidor. Esta creencia promueven un mal estilo de programación de los servicios web. Es más, no son servicios ya que se parecen mas a llamadas RPC o RMI. Esto es un error. No deben exponerse los objetos de negocio mediante un WebService. 
&lt;p&gt;Un escenario real: En un desarrollo para una empresa de reservas de hoteles, teniamos las clases Hotel, Habitacion, Reserva, Pasajero, Temporada y otras más. Un amigo se encargaba del desarrollo del cliente y sus necesidades eran claras, &amp;quot;necesito una lista con las disponibilidades (con los dias disponibles) y precios de las habitaciones de los hoteles en esos dias y la descripción de las comodidades o servicios que incluyen en esa temporada&amp;quot;. Este y otros requerimientos no se corresponden con ningún objeto del negocio, es decir, sencillamente no se resuelven serializando y enviando ningún objeto del negocio.   
&lt;h2&gt;La solución&lt;/h2&gt;
&lt;p&gt;La solución consiste en crear un Facade cuyos métodos representen los servicios que puede brindar la aplicación como por ejemplo: obtener disponibilidades de tal fecha a tal fecha para tantas personas en determinado sitio turístico, obtener nuevas reservas para un hotel determinado, reservar, cancelar reserva, etc. 
&lt;p&gt;Ahora, por lo general los métodos del Facade no tendrán problemas en cuanto a los tipos de parámetros a recibir ya que serán (repito, por lo general) tipos simples como int, DateTime, String, Boolean, Double, etc. Pero sí requerirán retornar al cliente tipos especiales que, como dije antes, no se corresponden con los objetos de negocio. Entonces esto ya no es una simple clase &amp;quot;ReservationFacade&amp;quot; sino que se trata de un componente (o layer) con sus propios tipos como Availability, Recommend, etc. Si bien estos tipos pueden, por sus nombres, parecer que pertenecen a los tipos del dominio en realidad no lo son. Por ejemplo, Recommend puede contener un destino o zona turística recomendada junto con una lista de ofertas de tipos de habitaciones con sus precios en distintos hoteles y los periodos de validez de estas recomendaciones.  
&lt;p&gt;Ventajas de este patron: 
&lt;ul&gt;
&lt;li&gt;Facil de responder a los cambios. Si el Web Service debe modificarse para ajustarse a los nuevos requerimientos del negocio entonces solo es necesario modificar el Facade. 
&lt;li&gt;Facil de mantener. Es posible modificar la estructura interna (refactoring) de las clases de negocio sin alterar el contrato con los clientes de WS. Ya que no se crean dependencia entre las clases de negocio con las aplicaciones clientas. 
&lt;li&gt;Responde a la idea de servicios. Los servicios se consumen en operaciones atómicas. Es decir, el servicio de &amp;quot;Reservar habitación&amp;quot; se realiza mediante un solo mensaje con toda la información necesaria y es el Facade quien se encarga de realizar todas las operaciones (seguramente en una transacción). 
&lt;li&gt;Son mas veloces. Por la misma razón que expongo arriba se realizan muchas menos idas y vueltas desde el servidor al cliente y viceversa.&lt;/ul&gt;
&lt;p&gt;La ventaja quizás mas importante es independizar el WS del resto de la aplicación ahorrandonos de tener que regenerar el WS (salvo cuando tocamos el Facade) y por lo tanto evitamos tener que regenerar los proxies en todos los cliente de nuestro WS y recompilar todo, tanto nosotros como todos nuestros clientes que pueden estar utilizando nuestros servicios somos más felices. 
&lt;p&gt;Otra ventaje que se deriva del punto anterior es que el versionado de nuestro servicio se simplifica considerablemente. 
&lt;p&gt;&lt;strong&gt;Lucas Ontivero&lt;/strong&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=3988747590285877710&amp;page=RSS%3a+%5bPatterns%5d+Distributed+Applications+using+Facade+Pattern&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=lucasontivero.spaces.live.com&amp;amp;GT1=lucasontivero"&gt;</description><comments>http://lucasontivero.spaces.live.com/Blog/cns!375AE0CCD1AF61CE!431.entry#comment</comments><guid isPermaLink="true">http://lucasontivero.spaces.live.com/Blog/cns!375AE0CCD1AF61CE!431.entry</guid><pubDate>Fri, 31 Aug 2007 20:50:53 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://lucasontivero.spaces.live.com/blog/cns!375AE0CCD1AF61CE!431/comments/feed.rss</wfw:commentRss><wfw:comment>http://lucasontivero.spaces.live.com/Blog/cns!375AE0CCD1AF61CE!431.entry#comment</wfw:comment><dcterms:modified>2007-09-01T15:25:47Z</dcterms:modified></item><item><title>[Patterns] Distributed Applications using FactoryMethod and ServiceLocator Patterns</title><link>http://lucasontivero.spaces.live.com/Blog/cns!375AE0CCD1AF61CE!430.entry</link><description>&lt;div&gt;&lt;font size=2&gt;
&lt;p&gt;En esta entrada vamos a ver la utilidad del patrón Service Locator para construir aplicaciones distribuidas. Los componentes de estas aplicaciones deben estar totalmente desacoplados y por lo tanto la mejor manera de hacerlo es mediante el consumo de servicios que obviamente respeten ciertos contratos. 
&lt;p&gt;Ok, largamos con el patrón FactoryMethod como patrón inicial para ver como llegamos al ServiceLocator. Entonces, basicamente, todo método que tiene por objetivo crear diferentes tipos de objetos implementa implementa el patrón FactoryMethod. Veamos un ejemplo:&lt;/font&gt; &lt;/div&gt;&lt;pre style="border-right:#eee 1px solid;padding-right:5px;border-top:#eee 1px solid;padding-left:5px;font-size:12px;padding-bottom:20px;overflow:auto;border-left:#eee 1px solid;width:95%;padding-top:5px;border-bottom:#eee 1px solid;font-family:courier new;height:350px;background-color:#fff"&gt; 1 &lt;font color=blue&gt;using&lt;/font&gt; System.Windows.Forms;
 2 
 3 &lt;font color=blue&gt;namespace&lt;/font&gt; MyDocumentManager
 4 {
 5         &lt;font color=blue&gt;enum&lt;/font&gt; DocumentExtensionEnum {DOC, PDF, XML};
 6 
 7         &lt;font color=green&gt;/* La clase Abstracta */&lt;/font&gt;
 8         &lt;font color=blue&gt;public&lt;/font&gt; abstract &lt;font color=blue&gt;class&lt;/font&gt; Document
 9         {
10                 &lt;font color=blue&gt;public&lt;/font&gt; abstract &lt;font color=blue&gt;void&lt;/font&gt; Show(Form container);
11         }
12 
13         &lt;font color=green&gt;/* Las clases concretas */&lt;/font&gt;
14         &lt;font color=blue&gt;public&lt;/font&gt; &lt;font color=blue&gt;class&lt;/font&gt; WordDocument : Document
15         {
16                 &lt;font color=blue&gt;public&lt;/font&gt; &lt;font color=blue&gt;override&lt;/font&gt; &lt;font color=blue&gt;void&lt;/font&gt; Show(Form container){&lt;font color=green&gt;/*...*/&lt;/font&gt;}
17         }
18 
19         &lt;font color=blue&gt;public&lt;/font&gt; &lt;font color=blue&gt;class&lt;/font&gt; PDFDocument : Document
20         {
21                 &lt;font color=blue&gt;public&lt;/font&gt; &lt;font color=blue&gt;override&lt;/font&gt; &lt;font color=blue&gt;void&lt;/font&gt; Show(Form container){&lt;font color=green&gt;/*...*/&lt;/font&gt;}
22         }
23 
24         &lt;font color=blue&gt;public&lt;/font&gt; &lt;font color=blue&gt;class&lt;/font&gt; XMLDocument : Document
25         {
26                 &lt;font color=blue&gt;public&lt;/font&gt; &lt;font color=blue&gt;override&lt;/font&gt; &lt;font color=blue&gt;void&lt;/font&gt; Show(Form container){&lt;font color=green&gt;/*...*/&lt;/font&gt;}
27         }
28 
29         &lt;font color=green&gt;/* La clase creadora o consumidora de documentos */&lt;/font&gt;
30         &lt;font color=blue&gt;public&lt;/font&gt; &lt;font color=blue&gt;class&lt;/font&gt; DocumentManager
31         {
32                 DocumentManager(&lt;font color=blue&gt;string&lt;/font&gt; filename)
33                 {
34                         Document doc = FactoryMethod(filename);
35                         doc.Show(&lt;font color=blue&gt;new&lt;/font&gt; DocumentViewerForm());
36                 }
37 
38                 &lt;font color=green&gt;/* Este es el metodo */&lt;/font&gt;
39                 &lt;font color=blue&gt;private&lt;/font&gt; Document FactoryMethod(&lt;font color=blue&gt;string&lt;/font&gt; filename)
40                 {
41                         Document doc;
42                         DocumentExtensionEnum extension = GetExtension(filename);
43 
44                         &lt;font color=green&gt;/* crea el tipo de documento adecuado segun la extension del archivo */&lt;/font&gt;
45                         &lt;font color=blue&gt;switch&lt;/font&gt;(extension){
46                                 &lt;font color=blue&gt;case&lt;/font&gt; DocumentExtensionEnum.DOC:
47                                 doc = &lt;font color=blue&gt;new&lt;/font&gt; WordDocument();
48                                 &lt;font color=blue&gt;break&lt;/font&gt;;
49                                 &lt;font color=blue&gt;case&lt;/font&gt; DocumentExtensionEnum.PDF:
50                                 doc = &lt;font color=blue&gt;new&lt;/font&gt; PDFDocument();
51                                 &lt;font color=blue&gt;break&lt;/font&gt;;
52                                 &lt;font color=blue&gt;case&lt;/font&gt; DocumentExtensionEnum.XML:
53                                 doc = &lt;font color=blue&gt;new&lt;/font&gt; XMLDocument();
54                                 &lt;font color=blue&gt;break&lt;/font&gt;;
55                         }
56                         retrun doc;
57                 }
58         }
59 }
60 &lt;/pre&gt;&lt;font size=2&gt;
&lt;p&gt;Este es un ejemplo claro, según la extensión del archivo, nos devuelve el objeto adecuado. El tema es ahora que en este método tenemos un switch hardcodeado! Es decir, no podemos agregarle otros tipos de objetos a crear sin modificar el código :( 
&lt;p&gt;Y aquí entra el patrón que nos convoca, el Service Locator. Se trata de un patrón creational el cual permite registrar servicios o componentes y luego solicitar una instacia de alguno de ellos. Veamos un poco de código:&lt;/font&gt;  &lt;pre style="border-right:#eee 1px solid;padding-right:5px;border-top:#eee 1px solid;padding-left:5px;font-size:12px;padding-bottom:20px;overflow:auto;border-left:#eee 1px solid;width:95%;padding-top:5px;border-bottom:#eee 1px solid;font-family:courier new;height:300px;background-color:#fff"&gt;&lt;font color=blue&gt;public&lt;/font&gt; &lt;font color=blue&gt;class&lt;/font&gt; ServiceLocator
{
        &lt;font color=blue&gt;private&lt;/font&gt; Dictionary&amp;lt;&lt;font color=blue&gt;string&lt;/font&gt;, &lt;font color=blue&gt;object&lt;/font&gt;&amp;gt; services = &lt;font color=blue&gt;new&lt;/font&gt; Dictionary&amp;lt;&lt;font color=blue&gt;string&lt;/font&gt;, &lt;font color=blue&gt;object&lt;/font&gt;&amp;gt;();

        &lt;font color=blue&gt;public&lt;/font&gt; &lt;font color=blue&gt;void&lt;/font&gt; AddService(&lt;font color=blue&gt;string&lt;/font&gt; serviceName, &lt;font color=blue&gt;object&lt;/font&gt; service)
        {
                &lt;font color=blue&gt;if&lt;/font&gt; (&lt;font color=blue&gt;string&lt;/font&gt;.IsEmptyOrNull(serviceName))
                &lt;font color=blue&gt;throw&lt;/font&gt; &lt;font color=blue&gt;new&lt;/font&gt; ArgumentNullException(&amp;quot;&lt;font color=magenta&gt;serviceName&lt;/font&gt;&amp;quot;);
                &lt;font color=blue&gt;if&lt;/font&gt; (service == &lt;font color=blue&gt;null&lt;/font&gt;)
                &lt;font color=blue&gt;throw&lt;/font&gt; &lt;font color=blue&gt;new&lt;/font&gt; ArgumentNullException(&amp;quot;&lt;font color=magenta&gt;service&lt;/font&gt;&amp;quot;);

                services.Add(serviceName, service);
        }

        &lt;font color=blue&gt;public&lt;/font&gt; &lt;font color=blue&gt;object&lt;/font&gt; GetService(&lt;font color=blue&gt;string&lt;/font&gt; serviceName)
        {
                &lt;font color=blue&gt;if&lt;/font&gt; (&lt;font color=blue&gt;string&lt;/font&gt;.IsEmptyOrNull(serviceName))
                &lt;font color=blue&gt;throw&lt;/font&gt; &lt;font color=blue&gt;new&lt;/font&gt; ArgumentNullException(&amp;quot;&lt;font color=magenta&gt;serviceName&lt;/font&gt;&amp;quot;);

                &lt;font color=blue&gt;if&lt;/font&gt; (services.ContainsKey(serviceName))
                &lt;font color=blue&gt;return&lt;/font&gt; services[serviceName];

                &lt;font color=blue&gt;return&lt;/font&gt; &lt;font color=blue&gt;null&lt;/font&gt;;
        }
}
&lt;/pre&gt;
&lt;p&gt;Aquí lo he implementado con un diccionario string-object para hacerlo mas facil pero despues voy a mostrar una alternativa mejor. Otra cosa, por lo general, solo existe una instancia de esta clase as'i que se implementa mediante un Singleton. 
&lt;p&gt;La ventaja que tenemos ahora es que podemos hacer una clase &amp;quot;Services Loader&amp;quot; la cual lea un archivo de configuración (seguramente deserealizando un xml) y que de acuerdo a eso cargue los servicios que hagan falta dentro del Service Locator. Esto es especialmente útil cuando queremos hacer un sistema plug-able porque podemos poner un assembly en un directorio y modificar nuestro xml de configuración de modo que esta clase Service Loader cargue ahora los nuevos servicios de nuestro assembly haciendo que estos esten disponibles para la aplicación. 
&lt;p&gt;A ver si se entiende bien! puedo por ejemplo:&lt;pre style="border-right:#eee 1px solid;padding-right:5px;border-top:#eee 1px solid;padding-left:5px;font-size:12px;padding-bottom:20px;overflow:auto;border-left:#eee 1px solid;width:95%;padding-top:5px;border-bottom:#eee 1px solid;font-family:courier new;height:200px;background-color:#fff"&gt;IStorageManager sm = (IStorageManager)serviceLocator.GetService(&amp;quot;&lt;font color=magenta&gt;Storage Service&lt;/font&gt;&amp;quot;);

&lt;font color=blue&gt;if&lt;/font&gt;(sm != &lt;font color=blue&gt;null&lt;/font&gt;)
{
        sm.Save(myPersistentObject);
}
&lt;font color=blue&gt;else&lt;/font&gt;
{
        IEventLogger ev = (IEventLogger)serviceLocator.GetService(&amp;quot;&lt;font color=magenta&gt;Event Logger Service&lt;/font&gt;&amp;quot;);
        &lt;font color=blue&gt;if&lt;/font&gt;(ev != &lt;font color=blue&gt;null&lt;/font&gt;)
        ev.WriteWarning(
        String.Format(&amp;quot;&lt;font color=magenta&gt;{0} wasn't persisted&lt;/font&gt;&amp;quot;, myPersistentObject.ToString()
        );

}&lt;/pre&gt;
&lt;p&gt;Bien, alguno debe estar pensando &amp;quot;y como hace un cast así! habria que validar que respete esa interface antes de castearla tan burramente!!!&amp;quot;. Y sí, quien piesa así tiene razón, el tema es que lo hago así por sencilles y porque lo que quiero mostrar es que de esta manera lo que hacemos es: primero preguntamos si tenemos tal o cual servicio y de ser así lo usamos. Con este patrón (que todavia no tiene buena forma) podemos agregarle, sin tocar el código, un servicio de logueo cualquiera (que implemente la IEventLogger por supuesto). También podemos ponerle, sacarle o cambiarle el servicio de Storage registrando por ejemplo bajo el nombre de &amp;quot;Storage Service&amp;quot; a cualquier servicio que implemente la interface IStorageManage como por ejemplo, &amp;quot;SQL Storage Service&amp;quot;, &amp;quot;Amazon Storage Services&amp;quot;, &amp;quot;Web Blog Storage Service&amp;quot;, etc.    
&lt;p&gt;Tanto que hablamos del &amp;quot;Service Loader&amp;quot; veamos como puede ser:&lt;br&gt;&lt;font size=1&gt;&lt;em&gt;(Antes que nada, si ven algo que no anda es porque en la máquina en que estoy escribiendo esta entrada no tengo el .Net Framework 2.0)&lt;/em&gt;&lt;/font&gt; 
&lt;p&gt;  &lt;pre style="border-right:#eee 1px solid;padding-right:5px;border-top:#eee 1px solid;padding-left:5px;font-size:12px;padding-bottom:20px;overflow:auto;border-left:#eee 1px solid;width:95%;padding-top:5px;border-bottom:#eee 1px solid;font-family:courier new;height:200px;background-color:#fff"&gt;[XmlRootAttribute(&amp;quot;&lt;font color=magenta&gt;ServiceCatalog&lt;/font&gt;&amp;quot;, Namespace=&amp;quot;&lt;font color=magenta&gt;http://www.temosoft.com.ar/ServiceLoader&lt;/font&gt;&amp;quot;, IsNullable = &lt;font color=blue&gt;false&lt;/font&gt;)]
&lt;font color=blue&gt;public&lt;/font&gt; &lt;font color=blue&gt;class&lt;/font&gt; ServiceCatalog
{
        &lt;font color=blue&gt;private&lt;/font&gt; Service[] services;
        &lt;font color=blue&gt;public&lt;/font&gt; Service[] Services
        {
                get{ &lt;font color=blue&gt;return&lt;/font&gt; services; }
                set{ services=value;  }
        }
}

[Serializable]
&lt;font color=blue&gt;public&lt;/font&gt; &lt;font color=blue&gt;class&lt;/font&gt; Service
{
        &lt;font color=blue&gt;private&lt;/font&gt; &lt;font color=blue&gt;string&lt;/font&gt;   serviceName;
        &lt;font color=blue&gt;private&lt;/font&gt; &lt;font color=blue&gt;string&lt;/font&gt;   assemblyName;
        &lt;font color=blue&gt;private&lt;/font&gt; &lt;font color=blue&gt;string&lt;/font&gt;   typeName;
        &lt;font color=blue&gt;private&lt;/font&gt; Boolean  isAvailable;

        [XmlAttribute]
        &lt;font color=blue&gt;public&lt;/font&gt; &lt;font color=blue&gt;string&lt;/font&gt; ServiceName
        {
                get { &lt;font color=blue&gt;return&lt;/font&gt; serviceName; }
                set { serviceName= value; }
        }

        [XmlAttribute]
        &lt;font color=blue&gt;public&lt;/font&gt; &lt;font color=blue&gt;string&lt;/font&gt; AssemblyName
        {
                get { &lt;font color=blue&gt;return&lt;/font&gt; AssemblyName; }
                set { AssemblyName= value; }
        }

        [XmlAttribute]
        &lt;font color=blue&gt;public&lt;/font&gt; &lt;font color=blue&gt;string&lt;/font&gt; TypeName
        {
                get { &lt;font color=blue&gt;return&lt;/font&gt; typeName; }
                set { typeName= value; }
        }


        [XmlAttribute]
        &lt;font color=blue&gt;public&lt;/font&gt; Boolean IsAvailable
        {
                get { &lt;font color=blue&gt;return&lt;/font&gt; isAvailable; }
                set { isAvailable= value; }
        }
}


&lt;font color=blue&gt;public&lt;/font&gt; &lt;font color=blue&gt;class&lt;/font&gt; ServiceLoader
{
        &lt;font color=blue&gt;public&lt;/font&gt; &lt;font color=blue&gt;void&lt;/font&gt; Load()
        {
                XmlSerializer serializer = &lt;font color=blue&gt;new&lt;/font&gt; XmlSerializer(&lt;font color=blue&gt;typeof&lt;/font&gt;(ServiceCatalog));
                FileStream fs = &lt;font color=blue&gt;new&lt;/font&gt; FileStream(&amp;quot;&lt;font color=magenta&gt;ServiceCatalog.xml&lt;/font&gt;&amp;quot;, FileMode.Open);
                ServiceCatalog servicesCatalog = (ServiceCatalog)serializer.Deserialize(fs);

                &lt;font color=blue&gt;foreach&lt;/font&gt;(Service s &lt;font color=blue&gt;in&lt;/font&gt; servicesCatalog.Services)
                {
                        &lt;font color=blue&gt;try&lt;/font&gt;{
                                Assembly asm = Assembly.Load(s.AssemblyName);
                                Type serviceType asm.GetType(s.TypeName);

                                ServiceLocator.Instance.AddService( s.ServiceName, Activator.CreateInstance(serviceType));
                        }&lt;font color=blue&gt;catch&lt;/font&gt;(Exception e){
                        }
                }
        }
}
&lt;/pre&gt;
&lt;p&gt;En este caso asuminos que el ServiceLocator es un Singleton. Es posible también hacer que cada servicio pueda recibir parámetros en su constructor. Ahora, como hacemos para mejorar esto? &lt;pre style="border-right:#eee 1px solid;padding-right:5px;border-top:#eee 1px solid;padding-left:5px;font-size:12px;padding-bottom:20px;overflow:auto;border-left:#eee 1px solid;width:95%;padding-top:5px;border-bottom:#eee 1px solid;font-family:courier new;height:300px;background-color:#fff"&gt;&lt;font color=blue&gt;public&lt;/font&gt; &lt;font color=blue&gt;static&lt;/font&gt; &lt;font color=blue&gt;class&lt;/font&gt; ServiceLocator
{
        &lt;font color=blue&gt;private&lt;/font&gt; &lt;font color=blue&gt;static&lt;/font&gt; ServiceLocator instance;
        &lt;font color=blue&gt;private&lt;/font&gt; &lt;font color=blue&gt;static&lt;/font&gt; &lt;font color=blue&gt;object&lt;/font&gt; instanceLock = &lt;font color=blue&gt;new&lt;/font&gt; &lt;font color=blue&gt;object&lt;/font&gt;();
        &lt;font color=blue&gt;private&lt;/font&gt; Dictionary&amp;lt;&lt;font color=blue&gt;object&lt;/font&gt;, &lt;font color=blue&gt;object&lt;/font&gt;&amp;gt; services = &lt;font color=blue&gt;new&lt;/font&gt; Dictionary&amp;lt;&lt;font color=blue&gt;object&lt;/font&gt;, &lt;font color=blue&gt;object&lt;/font&gt;&amp;gt;();

        &lt;font color=blue&gt;public&lt;/font&gt; ServiceLocator Instance
        {
                get
                {
                        &lt;font color=blue&gt;if&lt;/font&gt; (instance == &lt;font color=blue&gt;null&lt;/font&gt;)
                        {
                                &lt;font color=blue&gt;lock&lt;/font&gt; (instanceLock)
                                {
                                        &lt;font color=blue&gt;if&lt;/font&gt; (instance == &lt;font color=blue&gt;null&lt;/font&gt;)
                                        {
                                                instance = &lt;font color=blue&gt;new&lt;/font&gt; ServiceLocator();
                                        }
                                }
                        }
                        &lt;font color=blue&gt;return&lt;/font&gt; instance;
                }
        }

        &lt;font color=blue&gt;public&lt;/font&gt; &lt;font color=blue&gt;void&lt;/font&gt; Add(&lt;font color=blue&gt;object&lt;/font&gt; serviceKeyObject, &lt;font color=blue&gt;object&lt;/font&gt; service)
        {
                &lt;font color=blue&gt;if&lt;/font&gt; (serviceKeyObject==&lt;font color=blue&gt;null&lt;/font&gt;)
                &lt;font color=blue&gt;throw&lt;/font&gt; &lt;font color=blue&gt;new&lt;/font&gt; ArgumentNullException(&amp;quot;&lt;font color=magenta&gt;serviceKeyObject&lt;/font&gt;&amp;quot;);
                &lt;font color=blue&gt;if&lt;/font&gt; (service == &lt;font color=blue&gt;null&lt;/font&gt;)
                &lt;font color=blue&gt;throw&lt;/font&gt; &lt;font color=blue&gt;new&lt;/font&gt; ArgumentNullException(&amp;quot;&lt;font color=magenta&gt;service&lt;/font&gt;&amp;quot;);

                &lt;font color=blue&gt;if&lt;/font&gt; (!services.ContainKey(serviceKeyObject))
                services.Add(serviceKeyObject, service);
        }

        &lt;font color=blue&gt;public&lt;/font&gt; &lt;font color=blue&gt;object&lt;/font&gt; Get(&lt;font color=blue&gt;object&lt;/font&gt; serviceKeyObject)
        {
                &lt;font color=blue&gt;if&lt;/font&gt; (serviceName==&lt;font color=blue&gt;null&lt;/font&gt;)
                &lt;font color=blue&gt;throw&lt;/font&gt; &lt;font color=blue&gt;new&lt;/font&gt; ArgumentNullException(&amp;quot;&lt;font color=magenta&gt;serviceKeyObject&lt;/font&gt;&amp;quot;);

                &lt;font color=blue&gt;if&lt;/font&gt; (services.ContainsKey(serviceName))
                &lt;font color=blue&gt;return&lt;/font&gt; services[serviceName];

                &lt;font color=blue&gt;return&lt;/font&gt; &lt;font color=blue&gt;null&lt;/font&gt;;
        }

        &lt;font color=blue&gt;public&lt;/font&gt; T Get&amp;lt;T&amp;gt; (&lt;font color=blue&gt;object&lt;/font&gt; serviceKeyObject)
        {
                &lt;font color=blue&gt;object&lt;/font&gt; obj = Get(serviceKeyObject);
                &lt;font color=blue&gt;if&lt;/font&gt; (obj != &lt;font color=blue&gt;null&lt;/font&gt; &amp;amp;&amp;amp; (obj &lt;font color=blue&gt;is&lt;/font&gt; T))
                &lt;font color=blue&gt;return&lt;/font&gt; (T)obj;

                &lt;font color=blue&gt;return&lt;/font&gt; &lt;font color=blue&gt;null&lt;/font&gt;;
        }
}&lt;/pre&gt;
&lt;p&gt;Si no te sirvió usa el ObjectBuilder :) ,que además de implementar este y otros muchos patrones muy grosos, implementa Inyección de Dependencias para un desacople muy bien pensado. 
&lt;p&gt;&lt;strong&gt;Lucas Ontivero.&lt;/strong&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=3988747590285877710&amp;page=RSS%3a+%5bPatterns%5d+Distributed+Applications+using+FactoryMethod+and+ServiceLocator+Patterns&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=lucasontivero.spaces.live.com&amp;amp;GT1=lucasontivero"&gt;</description><comments>http://lucasontivero.spaces.live.com/Blog/cns!375AE0CCD1AF61CE!430.entry#comment</comments><guid isPermaLink="true">http://lucasontivero.spaces.live.com/Blog/cns!375AE0CCD1AF61CE!430.entry</guid><pubDate>Thu, 30 Aug 2007 20:08:38 GMT</pubDate><slash:comments>3</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://lucasontivero.spaces.live.com/blog/cns!375AE0CCD1AF61CE!430/comments/feed.rss</wfw:commentRss><wfw:comment>http://lucasontivero.spaces.live.com/Blog/cns!375AE0CCD1AF61CE!430.entry#comment</wfw:comment><dcterms:modified>2007-09-01T15:26:03Z</dcterms:modified></item></channel></rss>