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.

miércoles, 13 de agosto de 2014

La tienda de animales V

 Una vuelta de tuerca más

Patrones Estructurales

Hola de nuevo a todos y todas. En esta quinta entrada sobre los patrones GOF empezaremos una nueva tarea de modelado e implementación ya que hemos visto todos los patrones Creacionales. 

En esta nueva etapa veremos los patrones Estructurales que se caracterizan porque solucionan aspectos de composición (agregración) de clases y objetos.

Lo que vamos a hacer es añadir nuevas clases al sistema ya existente o modificaremos las que ya tenemos para añadir nuevas funcionalidades y características.


Definición de las nuevas características del sistema

Nuestro sistema va a tener la facultad de conectarse a un servicio web de un proveedor para actualizar nuestro stock y poder realizar pedidos online. De esta forma podremos crear un módulo de Inventario con el stock de productos de la tienda y que podremos tener almacenado en una BD local y en una copia de respaldo online.

Además, se creará un sistema de contabilidad básico que lleve el balance de la tienda con las ventas del día. Este sistema de contabilidad será particular para cada tipo de tienda.

Otra linea de negocio que nuestra tienda ha iniciado recientemente es  el club de amigos en defensa de los animales. Para ello se ha puesto en contacto con una red de asociaciones del gremio y colaborará buscando a personas entre sus clientes que quieran adoptar o apadrinar a un animal. Pero lo curioso del caso es que algunos de estos animales provienen de circos que se han visto obligados a cerrar por la crisis y presentan un plus un tanto especial. Son animales virtuosos que pueden realizar cosas como por ejemplo cantar, bailar, tocar el piano, etc...

Diagrama de Clases

El diagrama con las nuevas clases que se deben añadir al sistema también presenta algunas de las clases del modelado anterior, pero con algunas modificaciones. Ya que los nuevos requerimientos amplian las funcionalidades de algunas clases ya existentes.




Justificación de los patrones elegidos y clases implicadas

  • Adapter: Este patrón se utiliza cuando un cliente espera una interfaz determinada y la clase a utilizar presenta otra diferente, pero no la podemos cambiar porque por ejemplo, es un módulo externo compilado. Para solucionarlo se crea una nueva clase intermedia que añade un nivel de indirección con la misma interfaz que espera el cliente y se hace la petición a la interfaz adaptada. En nuestro ejemplo lo utilizaremos para acceder al webservice de un proveedor que nos envia su listado de artículos.
    • WebMethodTarget: Es la clase abstracta con la interfaz que espera el cliente.
    • WebMethodAdapter: la clase que implementa la interfaz.
    • WebMethodAdaptee: la clase que tiene la interfaz a adaptar, o sea el webservice.
  • Bridge: Permite desacoplar la interfaz de una funcionalidad de su implementación de forma que pueda cambiar sin modificarse la interfaz. Lo utilizaremos para representar el sistema de Balance de la tienda, ya al tener dos tipos de tienda, no tenemos que cambiar nada si modificamos la lógica del balance.
    • Balance: Tiene la interfaz con un enlace a la implementación.
    • SavageBalance, HomeBalance: el balance de cada tipo de tienda.
    • BalanceImpl: La interfaz de la implementación.
    • SavageBalanceImpl, HomeBalanceImpl: la implementación de la interfaz de la implementación.
  • Composite: Este patrón nos permite hacer objetos complejos a partir de objetos simples o similares. Para nuestro caso lo usaremos para modelar el club de amigos de los animales. Las partes simples serían cada uno de los miembros y las complejas serían los grupos o subgrupos que se componen de estos miembros.
    • Club: Tiene la interfaz para manejar las partes.
    • Group: es la parte compleja del patrón que se compone de Member.
    • Member: la parte simple del patrón.
  • Decorator: Permite añadir funcionalidades de forma dinámica a un objeto, es decir, en tiempo de ejecución. De esta forma se reduce la complejidad del modelo ya que se elimina la necesidad de herencia y facilita modificar el modelo sin tener que tocar la implementación.  En el nuevo modelo se utilizará para dar respuesta a los animales que tienen talentos especiales. Evitaremos complicar la herencia del árbol Animal añadiendo una nueva clase TalentAnimal que se encargará de los nuevos requerimientos.
    • Animal: A esta clase que ya estaba presente en el modelo inicial le queremos añadir nuevas funcionalidades. Ahora habrá animales que tienen talentos.
    • Bird, Reptil, Feline, Canine: Se les ampliará su funcionalidad.
    • TalentAnimal: Es la clase abstracta que tendrá la nueva funcionalidad.
    • DanceAnimal, SingAnimal: Clases que implementarán TalentAnimal y que serán las clase que representarán las nuevas funcionalidades.
  • Facade: Cuando tenemos un sistema con una gran complejidad ya que tiene multitud de clases y/0 su interacción es también alta podemos crear una clase Facade que haga de punto de entrada al sistema y de esta forma el cliente se abstrae del sistema y sólo utiliza la interfaz simplificada del mismo. Lo utilizaremos para modelar el inventario de la tienda que tiene una gran cantidad de clases y métodos.
    • Inventory: es la clase facade que abstrae el sistema de inventario.
    • ConnectionData: clase del sistema que crea la conexión a la BD.
    • LoadData: obtiene el contenido de la BD.
    • SaveData: almacena el inventario en la BD.
  • Flyweight: elimina o reduce la redundancia de información cuando vamos a necesitar muchas instancias de objetos que tienen la misma información básica. Los Articles de nuestra tienda disponen de campos como pueden ser la referencia o la cantidad por lo que al tener que crear muchos Articles bajamos el coste en cuanto a memoria utilizada.
    • Article: Es la clase abstracta con los campos comúnes.
    • ConcreteArticle: una implementación de un Article.
    • UnsharedConcreteArticle: otra implementación que no comparte información.
    • ArticleFactory: la clase que se encarga de gestionar la creación y mantenimiento de las instancias de Article creadas.
  • Proxy: Cuando necesitamos tener una representación de otro objeto porque la creación o el acceso al objeto real es muy costoso o presenta características especiales como por ejemplo la comprobación de permisos de acceso. En nuestro caso para poder modelar el acceso a la BD remota crearemos un proxy que representará una BD local y sólo accederá a la real cuando sea absolutamente necesario.
    • DB: Es la interfaz común que comparten el objeto real de acceso a la base de datos y el Proxy.
    • DBProxy: la clase que controla el acceso al objeto real SQLServer.
    • SQLServer: es la clase de acceso a la BD real.
Hasta aquí llegamos con esta entrega y os invito a seguir la siguiente en la que nos adentraremos en la implementación es este nuevo modelo ampliado con los patrones estructurales.
Hasta pronto.

viernes, 8 de agosto de 2014

La tienda de animales IV

¿Los contactos de la tienda son importantes? 

Patrón Factory Method

Hola de nuevo a todos y todas. En esta cuarta entrada sobre los patrones GOF seguiremos con el patrón Factory Method para implementar la agenda de contactos de la tienda.

Recordemos que nuestra tienda podía tener clientes representados por la clase Customer y proveedores representados por la clase Suplier.

Cada uno de ellos tendrá información específica que no es necesaria en el otro. Por ejemplo, el proveedor tendrá información sobre su compañía o el tipo de descuento que le hace a la tienda en sus productos.

El diagrama de clases es el que aparece a continuación:



Implementación

El patrón Factory Method tiene una estructura muy sencilla. La clase abstracta Contact es de la que heredan las clases Customer y Suplier que representan a los clientes y los proveedores. En esta hay un método abstracto que se encarga de formar el contenido de cada clase llamando a las clases de Data adecuadas según sea el tipo de Contact.

El código queda así:

public abstract class Contact
{
  List<Data> _datas = new List();

  public List<Data> Datas
  {
    get { return _datas; }
  }

  public Contact()
  {
    this.CreateData();
  }

  public abstract void CreateData();

  public void Show()
  {
    Console.WriteLine(">> " + GetType().Name);

    foreach (var item in _datas)
    {
       Console.WriteLine("\t- " +      item.GetType().Name);
    }
  }
}

public class Customer : Contact
{
  public override void CreateData()
  {
    Datas.Add(new PersonalData());
    Datas.Add(new SalesData());
  }
}

public class Supplier : Contact
{
  public override void CreateData()
  {
    Datas.Add(new CompanyData());
    Datas.Add(new DiscountData());
  }
}

Se puede ver una lista de Data en la clase Contact en la que se almacena la información de cada contacto. Con el método CreateData() se añaden objetos del tipo Data adecuados a la clase Contact correspondiente.

Lo bueno de esto es que si más adelante queremos crear otro tipo de Data sólo habría que hacer un Add en el métdo CreateData() de la subclase de Contact que esté relacionada.
Por ejemplo, si necestamos añadir información sobre las redes sociales que utiliza el contacto usualmente sólo habría que crear una clase que herede de Data y con los campos específicos.
Después en la clase Suplier habría que incluir en el método CreateData() un nuevo Add llamando al constructor de la nueva subclase de Data creada.
Por lo que se refiere a la clase abstracta Data por motivos de simplicidad no se han añadido campos y tampoco en sus subclases. Lo importante aquí es la herencia que se produce entre ellas. De esta forma podemos tener la lista de Data en cada subclase de Contact sin especificar el subtipo instanciado realmente.

public abstract class Data { }

public class SalesData : Data { }

public class CompanyData : Data { }

public class PersonalData : Data { }

public class DiscountData : Data { }

En resumen, hemos visto cómo podemos tener colecciones de objetos que amplian las propiedades de un objeto concreto de forma que estemos preparados ante futuros cambios del modelo sin afectar demasiado a nuestra implementación. Sólo hay que tocar un método añadiendo tantas lineas Add como nuevos subtipos de Data hayamos creado.

Un ejemplo de uso de este patrón en el cliente se resumiría a crear objetos de los subtipos de contact. En el codigo de ejemplo siguiente se utiliza un array como almacén de los Contact.

// Factory Method
Contact[] contacts = new Contact[2];

contacts[0] = new Customer();
contacts[1] = new Supplier();

contacts[0].Show();
contacts[1].Show();


Y esto es todo por ahora. En la próxima entrega hablaremos de los patrones Estructurales y mostraremos el siguiente módulo de la tienda de animales que utilizará estos patrones.

Hasta pronto.