Programación II. Guía No. 13 1 Facultad: Ingeniería Escuela: Computación Asignatura: Programación II Tema: Patrones de Diseño. Objetivos Implementar la aplicación de patrones de diseño como herramientas para el mejoramiento de la programación. Desarrollar aplicaciones usando patrones de diseño. Comprender las ventajas de aplicaciones de patrones de diseño como manera profesional de elaborar software. Materiales y Equipo Computadora con el software DevC++. Guía Número 13. Introducción Teórica Concepto de Patrón. Un patrón de diseño es: Una solución estándar para un problema común de programación. Una técnica para flexibilizar el código haciéndolo satisfacer ciertos criterios. Un proyecto o estructura de implementación que logra una finalidad determinada. Un lenguaje de programación de alto nivel. Una manera más práctica de describir ciertos aspectos de la organización de un programa. Conexiones entre componentes de programas. La forma de un diagrama de objeto o de un modelo de objeto. 2 Programación II. Guía No. 13 Ejemplos de Patrones. A continuación se presentan algunos ejemplos de patrones de diseño. A cada diseño de proyecto le sigue el problema que trata de resolver, la solución que aporta y las posibles desventajas asociadas. Un desarrollador debe buscar un equilibrio entre las ventajas y las desventajas a la hora de decidir que patrón utilizar. Lo normal es, como observará a menudo en la ciencia computacional y en otros campos, buscar el balance entre flexibilidad y rendimiento. Encapsulación (ocultación de datos). Problema: los campos externos pueden ser manipulados directamente a partir del código externo, lo que conduce a violaciones del invariante de representación o a dependencias indeseables que impiden modificaciones en la implementación. Solución: esconda algunos componentes, permitiendo sólo accesos estilizados al objeto. Desventajas: la interfaz no puede, eficientemente, facilitar todas las operaciones deseadas. El acceso indirecto puede reducir el rendimiento. Subclase (herencia). Problema: abstracciones similares poseen miembros similares (campos y métodos). Esta repetición es tediosa, propensa a errores y un verdadero problema durante el mantenimiento. Solución: herede miembros por defecto de una superclase, seleccione la implementación correcta a través de resoluciones sobre qué implementación debe ser ejecutada. Desventajas: el código para una clase está muy dividido, con lo que, potencialmente, se reduce la comprensión. La introducción de resoluciones en tiempo de ejecución introduce “overhead” (procesamiento extra). Iteración. Problema: los clientes que desean acceder a todos los miembros de una colección deben realizar un transversal especializado para cada estructura de datos, lo que introduce dependencias indeseables que impiden la ampliación del código a otras colecciones. Programación II. Guía No. 13 3 Solución: las implementaciones, realizadas con conocimiento de la representación, realizan transversales y registran el proceso de iteración. El cliente recibe los resultados a través de una interfaz estándar. Desventajas: la implementación fija el orden de iteración, esto es, no está controlada en absoluto por el cliente. Excepciones. Problema: los problemas que ocurren en una parte del código normalmente han de ser manipulados en otro lugar. El código no debe desordenarse con rutinas de manipulación de error, ni con valores de retorno para identificación de errores. Solución: introducir estructuras de lenguaje para arrojar e interceptar excepciones. Desventajas: es posible que el código pueda continuar aún desordenado. Puede ser difícil saber dónde será gestionada una excepción. Tal vez induzca a los programadores a utilizar excepciones para controlar el flujo normal de ejecución, que es confuso y por lo general ineficaz. Cuando no utilizar patrones de diseño. La primera regla de los patrones de diseño coincide con la primera regla de la optimización: “Del mismo modo que no es aconsejable optimizar prematuramente, no se deben utilizar patrones de diseño antes de tiempo”. Seguramente sea mejor implementar algo primero y asegurarse de que funciona, para luego utilizar el patrón de diseño para mejorar las debilidades; esto es cierto, sobre todo, cuando aún no ha identificado todos los detalles del proyecto (si comprende totalmente el dominio y el problema, tal vez sea razonable utilizar patrones desde el principio, de igual modo que tiene sentido utilizar los algoritmos más eficientes desde el comienzo en algunas aplicaciones). Procedimiento EJEMPLO No. 1 - Patrón de diseño compuesto. Bibliografía Guía 1 4 Programación II. Guía No. 13 Características: Identificar el escalar / clases primitivas y el vector / clases de contenedores. Crear una "interfaz" (mínimo común denominador) que pueden hacer todas las clases concretas "intercambiables". Todas las clases concretas declaran "una relación" a la interfaz. Todas las clases "contenedoras" se acoplan por ellas mismas a la interfaz (composición recursiva). Implementación de Patrón de diseño de comandos. #include <iostream> #include <vector> using namespace std; // Para utilizar la clase “vector” // Crea una "interfaz" class Component { public: virtual void traverse( ) = 0; }; // SuperClase Abstracta // Función virtual pura // Clase Escalar. Relación “es un” class Leaf : public Component { private: int value; public: Leaf(int val) { value = val; } void traverse( ) { cout << value << ' '; } // Constructor con parámetros // Función para mostrar los elementos del vector }; class Composite : public Component { private: vector < Component * > children; public: void add(Component * ele) { children.push_back(ele); } // Clase contenedora enlazada a la interfaz // Clase Vector. Relación “es un” // Contenedor enlazado con la interfaz /* Función para agregar elementos a la cola (vector) */ Programación II. Guía No. 13 5 // Función recursiva para mostrar los elementos del vector void traverse( ) { for (int i = 0; i < children.size( ); i++) children [i] -> traverse( ); // Uso de polimorfismo para delegar al hijo } }; int main( ) { Composite containers[4]; /* Crea un objeto de tipo Composite. En verdad se crea una matriz de 4 x n */ // Para agregar los datos a la primera fila(0) de la matriz for (int i = 0; i < 4; i++) for (int j = 0; j < 3; j++) containers [ i ].add(new Leaf(i * 3 + j)); // Agrega los elementos de las filas 2 a 4 en la matriz for (int i = 1; i < 4; i++) containers[0].add(&(containers[ i ])); // Rutina para mostrar todos los elementos de la matriz for (int i = 0; i < 4; i++) { cout << "Mostrando la fila " << i + 1 << endl; containers[i].traverse( ); cout << endl; } system("pause > nul"); return 0; } EJEMPLO No. 2 - Patrón de diseño Decorador. Características: Crear un "mínimo común denominador" que hace que las clases sean intercambiables. Crear una clase base de nivel dos para la funcionalidad opcional. La clase "Core" y "Decorador" declaran una relación "es un". La clase Decorador tiene una instancia del "mínimo común denominador". La clase Decorador delega para la clase de tipo “tiene un” objeto. Cree una clase Decorador derivada para cada adorno opcional. Decorador de las clases derivadas delega a la clase base y permite agregar cosas extras. El Cliente tiene la responsabilidad de componer configuraciones deseadas. 6 Programación II. Guía No. 13 #include <iostream> using namespace std; class Widget { public: virtual void draw( ) = 0; }; // Superclase Abstracta class TextField : public Widget { private: int width, height; // Clase "Principal”. Relación "es un" public: TextField(int w, int h) { width = w; height = h; } // Función virtual pura // Constructor con parámetros // Función virtual para mostrar los datos del campo de texto void draw( ) { cout << "TextField: " << width << ", " << height << '\n'; } }; class Decorator : public Widget { private: Widget * wid; public: Decorator(Widget * w) { wid = w; } void draw() { wid -> draw( ); } // Clase base de segundo nivel. Relación "es un" // Relación "tiene un" // Constructor con parámetros // Función virtual // Delegación a clase hija }; class BorderDecorator : public Decorator { public: BorderDecorator(Widget * w): Decorator(w){ } // Embellecimiento opcional // Función virtual para mostrar los datos del borde del decorador void draw() { Decorator :: draw( ); // Delegar hacia la clase base y cosas extras cout << " Se ha invocado a la clase BorderDecorator " << endl; } }; Programación II. Guía No. 13 class ScrollDecorator : public Decorator { public: ScrollDecorator(Widget * w): Decorator(w){ } 7 // Embellecimiento opcional // Función virtual para mostrar los datos del scroll del decorador void draw() { Decorator :: draw( ); // Delegar hacia la clase base y cosas extras cout << " Se ha invocado a la clase ScrollDecorator " << endl; } }; int main( ) { // El Cliente tiene la responsabilidad para componer configuraciones deseadas Widget * aWidget = new BorderDecorator(new BorderDecorator(new ScrollDecorator(new TextField(80, 24)))); aWidget -> draw( ); // Se invoca a la función draw con el puntero creado system("pause > nul"); return 0; } Análisis de Resultados Ejercicio 1: Implementar el código mostrado en el ejemplo No. 1 en un programa con DevC++, probarlo, entenderlo y explicar detalladamente la funcionalidad del mismo. Ejercicio 2: Implementar el código mostrado en el ejemplo No. 2 en un programa con DevC++, probarlo, entenderlo y explicar detalladamente la funcionalidad del mismo. 8 Programación II. Guía No. 13 Investigación Complementaria Investigar lo siguiente: ¿Qué otros tipos de patrones de diseño existen? Explicar el problema, la solución y las ventajas. (Al menos cuatro patrones distintos). Investigar sobre el Patrón Proxy – el cual protege de acceso al objeto original. Incluir un ejemplo de codificación de uso (en DevC++). 9 Programación II. Guía No. 13 Guía 13: Patrones de Diseño. Hoja de cotejo: Alumno: Máquina No: Docente: GL: 13 Fecha: EVALUACIÓN % CONOCIMIENTO Del 20 al 30% APLICACIÓN DEL CONOCIMIENTO Del 40% al 60% ACTITUD Del 15% al 30% TOTAL 100% 1-4 5-7 8-10 Conocimiento deficiente de los fundamentos teóricos Conocimiento y explicación incompleta de los fundamentos teóricos Conocimiento completo y explicación clara de los fundamentos teóricos No tiene actitud proactiva. Actitud propositiva y con propuestas no aplicables al contenido de la guía. Tiene actitud proactiva y sus propuestas son concretas. Nota