jueves, 28 de agosto de 2014

La tienda de animales VI

Stock online

Patrón Adapter y Flyweight

Hola de nuevo a todos y todas. Después de una semana de descanso volvemos con la sexta entrada sobre los patrones GOF. En este caso seguiremos con el patrón Adapter para implementar la conexión a los servicios web de un proveedor para actualizar nuestro stock y el patrón Flyweight que nos servirá para crear los artículos que obtendremos después con la conexión al webservice de nuestro proveedor.



Diagrama de Clases

Para el patrón Flyweight queda así:

 

El patrón Flyweight se utiliza para reducir gasto de recursos innecesarios y mejorar el rendimiento global. En nuestro caso al acceder al webservice del proveedor obtendremos una serie de artículos/productos que deberemos instanciar en nuestro sistema. Estos artículos tienen información común que la podemos generalizar en una clase padre.

Para el patrón Adapter el diagrama sería este:
 


El patrón Adapter se compone de tres clases que realizan todo el trabajo.

Imaginemos, por ejemplo, nuestro sistema de descarga de productos desde el proveeedor de la tienda. El proveedor nos ofrece un WebService que tiene una interfaz pública y que llamaremos en nuestro ejemplo WebMethodAdaptee.

Este web service no lo podemos tocar nosotros de ninguna manera y nuestro problema surge porque tenemos en nuestro sistema un módulo que se encarga de gestionar nuestro stock, y hasta ahora para recuperar el stock ha estado haciendo uso de un método con una interfaz distinta a la que ofrece el webservice. Vaya esto es un problema.

Pero aquí es donde aparece nuestro Adapter. Crearemos una clase,WebMethodAdapter, que incluirá un nivel de indirección extra entre el WebMethodTaget y el WebMethodAdaptee y posibilitará que estos dos puedan funcionar juntos.

Implementación

En primer lugar hablaremos de la parte que se encargará de la creación de los artículos con el patrón Flyweight. Para ello debemos crear una clase abstracta llamada Article que representará a los productos obtenidos desde el webservice del proveedor. Como se ve dispone de métodos y propiedades comunes a todos los productos.

public abstract class Article
{
        protected int _reference;
        protected int _quantity;

        public abstract void Remove(int quantity);
        public abstract void Add(int quantity);
        public abstract void Display();

}


A continuación debemos crea dos clases que hereden de Article. UnsharedConcreteArticle nos servirá para aquellos casos en los que no se deba compartir información y ConcreteArticle que será para cuando sí que haya información a compartir.

public class UnsharedConcreteArticle : Article
{
        public override void Remove(int quantity)
        {
            _quantity -= quantity;
        }

        public override void Add(int quantity)
        {
            _quantity += quantity;
        }

        public override void Display()
        {
            Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().ReflectedType.Name + " " + _quantity);
        }
}


public class ConcreteArticle : Article
{
        public override void Remove(int quantity)
        {
            _quantity -= quantity;
        }

        public override void Add(int quantity)
        {
            _quantity += quantity;
        }

        public override void Display()
        {
            Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().ReflectedType.Name + " " + _quantity);
        }
}


Por último, sólo nos queda crear la clase factoría que cree las instancias de los artículos según su tipo. La clase ArticleFactory dispone de una tabla Hash para devolver una instancia del tipo que recibe. 

public class ArticleFactory
{
        private Hashtable _articles = new Hashtable();

        public ArticleFactory()
        {
            _articles.Add(typeof(Aligator), new ConcreteArticle());
            _articles.Add(typeof(Cat), new ConcreteArticle());
            _articles.Add(typeof(Chamaleon), new ConcreteArticle());
            _articles.Add(typeof(Dingo), new ConcreteArticle());
            _articles.Add(typeof(Dog), new ConcreteArticle());
            _articles.Add(typeof(Eagle), new ConcreteArticle());
            _articles.Add(typeof(Lion), new ConcreteArticle());
            _articles.Add(typeof(Parrot), new ConcreteArticle());
        }

        public  Article GetArticle(Type key)
        {
            return (Article)_articles[key];
        }
}


A continuación seguiremos con el patrón Adapter que hace uso de este patrón Flyweight.

Para simular el webservice del proveedor crearemos la clase WebMethodAdaptee que tendrá un método público y nos dará como respuesta una lista de productos. Esto en un caso real podría ser un webservice que devolvería, por ejemplo, un json, un mensaje xml, etc...

public class WebMethodAdaptee
{
        public string[] SpecificRequest()
        {
            return new[] { "Aligator", "Cat", "Chamaleon", "Dingo", "Dog", "Eagle", "Lion", "Parrot" };
        }
}

El segundo punto a implementar sería la clase que debe poder conectarse al webservice y que ahora no puede. Nuestro WebMethodTarget. Realmente usaremos una clase abstracta que tendrá un método público a implementar y que será el que realmente se conecte con el WebService del proveedor.

public abstract class WebMethodTarget
{
        public abstract List<Article> Request();
}


Por último, debemos implementar la clase que realiza la indirección y permite que todo funcione. La clase WebMethodAdapter con la implementación de la clase abstracta.

public class WebMethodAdapter : WebMethodTarget
{
        public override List<Article> Request()
        {
            List<Article> articles = new List<Article>();




            // Flyweight

            ArticleFactory factory = new ArticleFactory();

            WebMethodAdaptee a = new WebMethodAdaptee();
            foreach (string item in a.SpecificRequest())
            {
                articles.Add(factory.GetArticle(getType(item)));
            }
            return articles;
        }

        private Type getType(string item)
        {
            switch (item)
            {
                case "Aligator":
                    return typeof(Aligator);
                case "Cat":
                    return typeof(Cat);
                 case "Lion":
                    return typeof(Lion);
                 case "Chamaleon":
                    return typeof(Chamaleon);
                 case "Dingo":
                    return typeof(Dingo);
                default:
                    return typeof(Eagle);
            }
        }
}




Podemos ver cómo se ha incluido el uso del patrón Flyweight a la hora de crear los Article. Cuando recuperamos el artículo desde el webservice miramos su tipo y en función de este llamamos a la clase factoría que nos devuelve una instancia de este tipo de artículo.

Hasta aaquí esta entrada en la que hemos visto cómo podemos solucionar problemas relacionados con la incompatibilidad entre interfaces y cómo mejorar el rendimiento del sistema reduciendo el consumo de memoria.

Hasta pronto.

No hay comentarios:

Publicar un comentario