Técnicas avanzadas de programación Fundamentos de programación orientada a objetos
Índice <ul><li>Introducción </li></ul><ul><li>Generalización o abstracción </li></ul><ul><li>Encapsulamiento </li></ul><ul...
Introducción
¿Qué es un método? <ul><li>“ No basta tener ingenio, lo principal es aplicarlo bien”  (Descartes, Discurso del método) </l...
Cambio de mentalidad Métodos Métodos Métodos Procedimiento 1 Procedimiento 2 Datos Datos Objeto Datos Objeto Datos Paradig...
Objetivos de la ingeniería (I) <ul><li>Corrección : el software realiza la especificación de requisitos </li></ul><ul><li>...
Objetivos de la ingeniería (II) <ul><li>Facilidad de uso : tanto si el usuario es un consumidor final (se habla de “interf...
Principios y reglas de la ingeniería OO <ul><li>Para cumplir los objetivos tenemos que aplicar principios. Cada principio ...
Principios y objetivos Encapsulamiento: Utilizamos los servicios de un objeto a través de su interfaz externo Generalizaci...
Generalización o abstracción
Generalización: mantener la coherencia (I) <ul><li>Toda clase debe aspirar a ser una representación  genérica  de una enti...
Generalización: mantener la coherencia (II) <ul><li>Mantener  la coherencia de los métodos : tratemos de hacer un componen...
Generalización: generalizar datos y métodos <ul><li>Generalizar tipos de datos y métodos : la clase debe cumplir su rol en...
Generalización: amplia cobertura del servicio <ul><li>Amplia cobertura del servicio . Cuando decimos que una clase tiene u...
Generalización: minimizar información global <ul><li>Minimizar la información global . Tratemos de minimizar las referenci...
Generalización: gestión de excepciones <ul><li>Una excepción es una situación anómala que normalmente interrumpe el flujo ...
Generalización: optimizar con precaución <ul><li>Como norma elemental conviene optimizar una vez que funciona el programa....
Encapsulamiento
Encapsulamiento: introducción (I) <ul><li>El principio de encapsulamiento es una forma moderna de denominar al tradicional...
Encapsulamiento: introducción (II) <ul><li>Visión externa (interfaz): definición del mensaje </li></ul><ul><li>Visión inte...
Encapsulamiento: introducción (III) <ul><li>Algunas definiciones: </li></ul><ul><li>“ Consiste en separar los aspectos ext...
Encapsulamiento de clases <ul><li>Siguiendo la metáfora del equipo de música debemos diferenciar en nuestras clases lo que...
Encapsulamiento: ocultar estructuras y algoritmos internos <ul><li>Las estructuras de datos que utiliza una clase internam...
Modularidad
Modularidad: introducción (I) <ul><li>Un diseño modular se basa en la conocida estrategia de “divide y vencerás”. Descompo...
Modularidad: introducción (II) <ul><li>La modularidad facilita la reusabilidad y reduce costes, pero usada con prudencia <...
Modularidad: introducción (III) <ul><li>Hay diversas condiciones que permiten llegar a la modularidad: </li></ul><ul><ul><...
Modularidad: bajo acoplamiento (I) <ul><li>Cuando hablamos de un diseño modular hablamos de  bajo acoplamiento o poca depe...
Modularidad: bajo acoplamiento (II) <ul><ul><li>Regla de la  continuidad  modular: debemos diseñar y programas de tal form...
Modularidad: comprensibilidad <ul><li>Antes dijimos que si si los módulos no obedecen a la lógica del dominio, no son legi...
Modularidad: trazabilidad <ul><li>Se debe representar la  continuidad  entre los conceptos del proceso de desarrollo. </li...
Modularidad: arquitectura en capas <ul><li>De todo lo anterior (coherencia, bajo acoplamiento, etc.) se deduce que gran pa...
Modularidad: arquitectura en tres capas <ul><li>En la práctica, sobre todo en aplicaciones que no son muy grandes,  se sue...
Jerarquía
Jerarquía: introducción <ul><li>Las dos formas más usuales de jerarquía de clases son : </li></ul><ul><ul><li>Jerarquía de...
Jerarquía: herencia y redefinición <ul><li>La herencia es una: </li></ul><ul><ul><li>Forma de abstracción. Primero nos cen...
Jerarquía: herencia y polimorfismo <ul><li>Un nombre puede denotar instancias de muchas  clases diferentes , siempre que e...
Jerarquía: herencia y ligadura dinámica <ul><li>Un ejemplo de polimorfismo en el que la llamada (ligadura) al método se re...
Jerarquía: herencia y clases abstractas <ul><li>En nuestro ejemplo de las figuras el programador no ha incluido la impleme...
Clases abstractas en diferentes lenguajes Eiffel deferred  class Figura feature dibujar is  deferred  end ... Java abstrac...
Jerarquía: agregación <ul><li>Encontrar clases agregadoras es: </li></ul><ul><ul><li>Forma de abstracción. Primero nos cen...
Ejemplos de agregación <ul><li>Un ejemplo de composición con la librería Swing para hacer applets (clase  JApplet ). La pa...
Upcoming SlideShare
Loading in …5
×

Informatica

593 views

Published on

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
593
On SlideShare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
10
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Informatica

  1. 1. Técnicas avanzadas de programación Fundamentos de programación orientada a objetos
  2. 2. Índice <ul><li>Introducción </li></ul><ul><li>Generalización o abstracción </li></ul><ul><li>Encapsulamiento </li></ul><ul><li>Modularidad </li></ul><ul><li>Jerarquía </li></ul>
  3. 3. Introducción
  4. 4. ¿Qué es un método? <ul><li>“ No basta tener ingenio, lo principal es aplicarlo bien” (Descartes, Discurso del método) </li></ul><ul><li>Objetivos </li></ul><ul><li>Principios (axiomas) </li></ul><ul><li>Reglas de formación (notación). </li></ul><ul><li>Reglas de transformación (lo que se debe hacer para cumplir los principios). </li></ul><ul><li>Modelo de proceso (metarreglas que indican el orden de actividades) </li></ul>“ Primero, no admitir como verdadera cosa alguna que no supiese con evidencia [...]. No comprender en mis juicios nada más que lo que se presentase tan clara y distintamente, que no hubiese ninguna ocasión de ponerlo en duda” “ Dividir cada una de las dificultades que examine en cuantas partes fuese posible y en cuantas requiere su mejor solución” “ Conducir ordenadamente mis pensamientos empezando por los objetos más simples y más fáciles de conocer, para ir ascendiendo poco a poco, gradualmente, hasta el conocimiento de los más compuestos” “ Hacer en todo unos recuentos tan integrales y unas revisiones tan generales que llegase a estar seguro de no omitir nada” (Descartes, Discurso del método)
  5. 5. Cambio de mentalidad Métodos Métodos Métodos Procedimiento 1 Procedimiento 2 Datos Datos Objeto Datos Objeto Datos Paradigma orientado a objetos: Paradigma tradicional: Objeto
  6. 6. Objetivos de la ingeniería (I) <ul><li>Corrección : el software realiza la especificación de requisitos </li></ul><ul><li>Robustez : capacidad de reaccionar ante condiciones excepcionales </li></ul><ul><li>Extensible (facilidad de mantenimiento): poder cambiarlo en función de modificaciones de los requisitos. Para ello, es muy importante usar principios de calidad en el diseño: modularidad, encapsulamiento, etc. </li></ul><ul><li>Reutilizable : poder ser utilizado en otras aplicaciones </li></ul>
  7. 7. Objetivos de la ingeniería (II) <ul><li>Facilidad de uso : tanto si el usuario es un consumidor final (se habla de “interfaces amistosos”), como si es otro programador. En este último sentido una buena especificación de servicios, API o Application Programing Interface, ahorra costes de mantenimiento y reutilización. </li></ul><ul><li>Portabilidad : usable en diversos entornos. </li></ul><ul><li>Integrable (compatibilidad): posibilidad de compartir datos con otras aplicaciones (integración de datos o integración por medio de conexión) </li></ul><ul><li>Verificable : facilidad para poner a prueba la aplicación </li></ul>
  8. 8. Principios y reglas de la ingeniería OO <ul><li>Para cumplir los objetivos tenemos que aplicar principios. Cada principio se realiza mediante la aplicación de reglas: </li></ul><ul><li>1. Generalización o abstracción. Reglas: </li></ul><ul><ul><li>Mantener la coherencia de clases </li></ul></ul><ul><ul><li>Mantener la coherencia de métodos </li></ul></ul><ul><ul><li>Generalizar los tipos de datos y métodos </li></ul></ul><ul><ul><li>Amplia cobertura del servicio </li></ul></ul><ul><ul><li>Minimizar la información global </li></ul></ul><ul><ul><li>Gestión de excepciones </li></ul></ul><ul><ul><li>Precaución con la optimización </li></ul></ul><ul><li>2. Encapsulamiento. Reglas: </li></ul><ul><ul><li>Encapsular las clases </li></ul></ul><ul><ul><li>Ocultar estructuras y algoritmos internos </li></ul></ul><ul><li>3. Modularidad. Reglas: </li></ul><ul><ul><li>Minimizar el acoplamiento. </li></ul></ul><ul><ul><li>Comprensibilidad y trazabilidad. </li></ul></ul><ul><ul><li>Arquitectura en capas. </li></ul></ul><ul><li>4. Jerarquía. Reglas: </li></ul><ul><ul><li>Definir orden de herencia sin abusar de la profundidad </li></ul></ul><ul><ul><li>Definir orden de composición </li></ul></ul>
  9. 9. Principios y objetivos Encapsulamiento: Utilizamos los servicios de un objeto a través de su interfaz externo Generalización: Centrarnos en lo genérico y eliminar u ocultar detalles (el cómo) Modularidad Descomponemos de forma lógica CORRECCION ROBUSTEZ EXTENSIBILIDAD REUSABILIDAD Menor coste Mayor calidad Jerarquía Ordenamos por niveles de herencia y composición
  10. 10. Generalización o abstracción
  11. 11. Generalización: mantener la coherencia (I) <ul><li>Toda clase debe aspirar a ser una representación genérica de una entidad del dominio del problema o del dominio de la aplicación. Genérica o abstracta no significa que hace de todo, sino que cumple su papel de forma genérica. Las siguientes reglas nos permiten hacer software lo más genérico posible: </li></ul><ul><li>Mantener la coherencia o cohesión de la clase : una clase tiene un rol (papel o función) o un conjunto de roles lógicamente relacionados. Si tiene varios roles que no están relacionados resulta incoherente. Buenos ejemplos: </li></ul><ul><ul><ul><li>class ventana_configuración { ....} </li></ul></ul></ul><ul><ul><ul><li>class control_acceso_usuario { .... } </li></ul></ul></ul><ul><li>Pero no: </li></ul><ul><ul><ul><li>class calculador_e_interfaz_ de calculo { ... } </li></ul></ul></ul><ul><ul><ul><li>class de_todo_un_poco { ... } </li></ul></ul></ul>
  12. 12. Generalización: mantener la coherencia (II) <ul><li>Mantener la coherencia de los métodos : tratemos de hacer un componente de software que haga una cosa, para que la haga bien. Una parábola: </li></ul><ul><ul><li>Un pato se acerca a un delfín y le dice “Observa mi superioridad, soy capaz de volar andar y nadar”, a lo que el delfín responde “Bien, pero tu nadas lentamente, vuelas de manera pesada y andas con torpeza, mientras que yo nado muy bien”. </li></ul></ul><ul><li>La moraleja es que el software es más correcto, robusto y reutilizable si se parece al delfín de la parábola, no al pato. </li></ul><ul><li>En el siguiente ejemplo el método hace tres cosas: pide por teclado el radio del circulo, calcula el área y la muestra: </li></ul><ul><ul><ul><li>void funcion_incoherente () throws IOException { </li></ul></ul></ul><ul><ul><ul><li>float radio, area; </li></ul></ul></ul><ul><ul><ul><li>String cadena_teclado; </li></ul></ul></ul><ul><ul><ul><li>BufferedReader entrada = new BufferedReader(new InputStreamReader(System.in)); </li></ul></ul></ul><ul><ul><ul><li>System.out.println( &quot;Teclee el radio del círculo:&quot;); </li></ul></ul></ul><ul><ul><ul><li>cadena_teclado = entrada.readLine(); </li></ul></ul></ul><ul><ul><ul><li>radio = Float.parseFloat( cadena_teclado ); </li></ul></ul></ul><ul><ul><ul><li>area = radio * radio * 3.1416F; </li></ul></ul></ul><ul><ul><ul><li>System.out.println( &quot;El área es &quot; + area); </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><li>¿Cómo se haría de manera coherente o cohesiva? </li></ul>
  13. 13. Generalización: generalizar datos y métodos <ul><li>Generalizar tipos de datos y métodos : la clase debe cumplir su rol en una enorme variedad de contextos . Se trata de generalizar respecto a los métodos y respecto a los tipos de datos: </li></ul><ul><ul><li>Respecto a los métodos, los parámetros pueden ser valores nulos, extremos o situados fuera de los limites. Aún así, el comportamiento (método) de la clase debe ser correcto y robusto. </li></ul></ul><ul><ul><li>Respecto a los tipos de datos. Por ejemplo, una clase que ordena un vector de figuras en función de su extensión o de su perímetro puede ser: </li></ul></ul><ul><ul><ul><li>class organizador_figuras { .... } </li></ul></ul></ul><ul><ul><li>Un ejemplo de escasa generalización sería el siguiente: </li></ul></ul><ul><ul><ul><li>class ordenador_perímetro_círculos { ... } </li></ul></ul></ul><ul><ul><ul><li>class ordenador_extensión_rectángulo { ... } </li></ul></ul></ul><ul><li>Para generalizar nos apoyamos en la gestión de excepciones, la herencia y el polimorfismo. </li></ul><ul><li>¿Cuál de estas dos clases representa de forma genérica (abstracta) su posición? </li></ul>class FIGURA { Point Posicion; ..... } class FIGURA { int pos_x; int pos_y; ..... }
  14. 14. Generalización: amplia cobertura del servicio <ul><li>Amplia cobertura del servicio . Cuando decimos que una clase tiene un rol estamos diciendo que proporciona un servicio. Trataremos de hacer que el servicio sea de amplio espectro, no limitándose al contexto presente . Esta es una situación muy común, por ejemplo nuestros equipos de música tienen numerosas funciones, aunque la mayoría de los usuarios sólo usan una parte de ellas. Sería absurdo que los creadores de estos equipos los hubieran diseñado para usuarios que fueran como ellos. </li></ul><ul><li>Lo mismo ocurre con las clases, darán un servicio por medio de numerosas funciones, aunque lo normal es que la mayoría de los usuarios no las usen todas. </li></ul><ul><li>Una de las formas de implementar una cobertura amplia es usar la sobrecarga de métodos: </li></ul><ul><ul><li>void imprimir( String cadena ) {....} </li></ul></ul><ul><ul><li>void imprimir( Figura fig ) {....} </li></ul></ul><ul><ul><li>void imprimir( Imagen img ) {....} </li></ul></ul>
  15. 15. Generalización: minimizar información global <ul><li>Minimizar la información global . Tratemos de minimizar las referencias externas. El uso de objetos globales impone restricciones a la reutilización del software. Resulta más adecuado manejar argumentos. En este pequeño ejemplo el método usa float base , que se le pasa como argumento: </li></ul><ul><ul><ul><li>public float calcular_cuadrado( float base ) { </li></ul></ul></ul><ul><ul><ul><li>return (base * base); </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><li>Una ventaja de esta versión es que resulta evidente que el interfaz del método, public float calcular_cuadrado( float base ) , usa un tipo float para el cálculo. La dependencia es evidente. En este otro ejemplo el método usa datos globales (concretamente son atributos static de la clase calculador ). Pero este uso no aparece en el interfaz del método: </li></ul><ul><ul><ul><li>public void calcular_cuadrado( ) { </li></ul></ul></ul><ul><ul><ul><li>calculador.resultado = calculador.base * calculador. base; </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><li>Esta forma de programar hace que la dependencia del método respecto a los datos no sea explicita. </li></ul>
  16. 16. Generalización: gestión de excepciones <ul><li>Una excepción es una situación anómala que normalmente interrumpe el flujo lógico del programa. Programar con generalidad también implica hacer aplicaciones que superen estas situaciones. En el siguiente ejemplo protegemos a la aplicación de: </li></ul><ul><ul><li>Un error en la entrada por teclado. </li></ul></ul><ul><ul><li>Un error de conversión de texto a tipo numérico. </li></ul></ul><ul><li>Gracias a este tratamiento de excepciones la aplicación no se paraliza, sino que reacciona ante el problema: </li></ul><ul><ul><ul><ul><li>try { </li></ul></ul></ul></ul><ul><ul><ul><ul><li>/* Creo el objeto 'entrada', es un lector de entradas por teclado */ </li></ul></ul></ul></ul><ul><ul><ul><ul><li>BufferedReader entrada = new BufferedReader(new InputStreamReader(System.in)); </li></ul></ul></ul></ul><ul><ul><ul><ul><li>System.out.print(&quot;Escriba el radio: &quot;); </li></ul></ul></ul></ul><ul><ul><ul><ul><li>c = entrada.readLine(); // Leo un String de la entrada de teclado </li></ul></ul></ul></ul><ul><ul><ul><ul><li>radio = Double.parseDouble(c); // Convierto el String en double </li></ul></ul></ul></ul><ul><ul><ul><ul><li>System.out.print(&quot;El área es: &quot; + 3.1416 * radio * radio); </li></ul></ul></ul></ul><ul><ul><ul><ul><li>} catch ( NumberFormatException e ) { </li></ul></ul></ul></ul><ul><ul><ul><ul><li>System.out.print( &quot;Error en el formato del número&quot; ); </li></ul></ul></ul></ul><ul><ul><ul><ul><li>} catch ( IOException e ) { </li></ul></ul></ul></ul><ul><ul><ul><ul><li>System.out.print( &quot;Error de entrada&quot; ); </li></ul></ul></ul></ul><ul><ul><ul><ul><li>} </li></ul></ul></ul></ul>
  17. 17. Generalización: optimizar con precaución <ul><li>Como norma elemental conviene optimizar una vez que funciona el programa. </li></ul><ul><li>Con frecuencia los programadores invierten demasiado esfuerzo intentando optimizar partes del código que se usan con poca frecuencia. Se trata de comparar los costes con los posibles (y normalmente escasos) beneficios. </li></ul><ul><li>La optimización generalmente amenaza la comprensibilidad, extensibilidad y reusabilidad del software. </li></ul><ul><li>Como norma general: es más importante hacer software legible y sensato que software optimizado e ilegible. </li></ul><ul><li>Ejemplo de código JDBC optimizado y poco legible: </li></ul><ul><ul><li>ResultSet rs = DriverManager.getConnection( &quot;jdbc:mysql://localhost/prueba&quot;,&quot;root&quot;, &quot;palabra“). createStatement().executeQuery( sentencia ); </li></ul></ul>
  18. 18. Encapsulamiento
  19. 19. Encapsulamiento: introducción (I) <ul><li>El principio de encapsulamiento es una forma moderna de denominar al tradicional principio de ocultamiento de la información. El principio nos indica que debemos hacer que los detalles de la clase estén ocultos para el exterior (también se denomina implementación encapsulada). </li></ul><ul><li>Es un principio de la ingeniería en general. Si estamos diseñando un equipo de música no parece adecuado que permitamos al usuario operar sobre las placas para cambiar el volumen o el tono. Los botones del equipo son el interfaz del sistema, la implementación queda encapsulada (oculta). </li></ul>
  20. 20. Encapsulamiento: introducción (II) <ul><li>Visión externa (interfaz): definición del mensaje </li></ul><ul><li>Visión interna (implementación): operaciones concretas </li></ul>class CUBO { .... Rotar( GRADO g); }; CUBO::Rotar( GRADO g) { .... } (C++)
  21. 21. Encapsulamiento: introducción (III) <ul><li>Algunas definiciones: </li></ul><ul><li>“ Consiste en separar los aspectos externos del objeto, a los cuales puede acceder otro objeto, de los detalles internos de implementación, que quedan ocultos para los demás” (RUMBAUGH, 1991) </li></ul><ul><li>“ El encapsulamiento es el proceso de almacenar en un mismo compartimento los elementos de una abstracción que constituyen su estructura y comportamiento; sirve para separar el interfaz contractual de una abstracción y su implementación” (BOOCH, 1994) </li></ul>
  22. 22. Encapsulamiento de clases <ul><li>Siguiendo la metáfora del equipo de música debemos diferenciar en nuestras clases lo que es público de lo que es privado. </li></ul><ul><li>Una aplicación general de este principio implica que los atributos serán privados y sólo se puede acceder a ellos desde los métodos públicos de la clase. </li></ul><ul><li>Ventaja: desde el código de la clase controlamos el acceso a los atributos. En caso de fallo o modificación del código, el programador comprueba los métodos de la clase que modifican ese dato y no tiene que revisar todo el código de los otros archivos. Además evitamos accesos indeseados que puedan modificarlos de forma no coherente con otros datos. Los métodos públicos son el intermediario (interfaz) entre los datos y los otros objetos: </li></ul>Método 1 Método 2 Datos Objeto Mensajes Los métodos públicos de la clase son el interfaz de la clase
  23. 23. Encapsulamiento: ocultar estructuras y algoritmos internos <ul><li>Las estructuras de datos que utiliza una clase internamente (por ejemplo un vector o un árbol) no deben ser accesibles para otras clases. </li></ul><ul><li>Por la misma razón los algoritmos internos deben quedar ocultos. Por ejemplo, la mayor parte de las modernas librerías de software tienen métodos para ordenar listas. Desde fuera el programador solo debe conocer el interfaz del método y lo que hace. No accedemos al interior del algoritmo: </li></ul><ul><ul><ul><li>/* Llamo al método static sort() de la clase Collections, le </li></ul></ul></ul><ul><ul><ul><li>paso como primer arg la lista y como segundo arg un objeto comparador */ </li></ul></ul></ul><ul><ul><ul><li>Collections.sort( lista, new comparador() ); </li></ul></ul></ul>
  24. 24. Modularidad
  25. 25. Modularidad: introducción (I) <ul><li>Un diseño modular se basa en la conocida estrategia de “divide y vencerás”. Descomponer de forma lógica y robusta el dominio de la aplicación. </li></ul><ul><li>Para conseguir la modularidad también debemos aplicar las reglas de coherencia de métodos y clases que vimos con el principio de generalidad , es decir, hacer que nuestros componentes sean especialistas. </li></ul>Analizador Fondos Fondo Inversión Interfaz Usuario Recomendación Fondos de Inversión estudiar alternativas obtener datos análisis datos para presentación
  26. 26. Modularidad: introducción (II) <ul><li>La modularidad facilita la reusabilidad y reduce costes, pero usada con prudencia </li></ul>Coste Número de módulos Coste por interfaces Coste por módulo
  27. 27. Modularidad: introducción (III) <ul><li>Hay diversas condiciones que permiten llegar a la modularidad: </li></ul><ul><ul><li>Descomposición funcional . Ver cada módulo como un especialista (aplicación de la regla de la coherencia). </li></ul></ul><ul><ul><li>Bajo acoplamiento . Además de ser especialistas tienen la mayor autonomía posible. </li></ul></ul><ul><ul><li>Comprensibles para un observador externo . Esto es obvio, pero no es tan común como parece. El objetivo es que cada módulo sea comprensible de forma independiente (cómo mucho obligar a un somero repaso de otros módulos), para ello los módulos deben obedecer a la lógica del dominio, ser legibles y estar bien documentados. </li></ul></ul><ul><ul><li>De 1 y 3 se deduce la condición de la trazabilidad . </li></ul></ul>
  28. 28. Modularidad: bajo acoplamiento (I) <ul><li>Cuando hablamos de un diseño modular hablamos de bajo acoplamiento o poca dependencia entre módulos . La regla del bajo acoplamiento implica: </li></ul><ul><ul><li>Interfaces pequeños: que los métodos públicos que intercambian información con otros módulos sean: </li></ul></ul><ul><ul><ul><li>El menor número posible. </li></ul></ul></ul><ul><ul><ul><li>Pequeños. Pocos argumentos. Si un método tiene muchos parámetros, probablemente hay revisar el diseño o encapsular los parámetros en una clase. </li></ul></ul></ul><ul><ul><li>En el siguiente ejemplo tenemos dos versiones de un método. El segundo método no sólo tiene menos argumentos, además resulta más comprensible: </li></ul></ul>fabrica.solicitar_pedido( Fec, Hora, CodComer, Cantidad, PVP, ModoEntrega ) fabrica.solicitar_pedido( pedido nuevo_pedido )
  29. 29. Modularidad: bajo acoplamiento (II) <ul><ul><li>Regla de la continuidad modular: debemos diseñar y programas de tal forma que pequeños cambios en un módulo producen a lo sumo pequeños cambios en otro. Evidentemente, esto facilita la extensibilidad y minimiza los costes de mantenimiento. </li></ul></ul><ul><ul><li>Regla de la protección modular: los errores en un módulo afectan como mucho a módulos adyacentes. </li></ul></ul><ul><ul><li>Regla de la comunicación explicita : la comunicación entre módulos es clara. Normalmente por medio de interfaces con pocos parámetros y sin usar información global (que hace que la interacción quede oculta). </li></ul></ul><ul><ul><li>Encapsular la implementación. También en los módulos hay que diferenciar lo público de lo privado. Un cambio en la parte privada no debería afectar al interfaz del módulo. </li></ul></ul>
  30. 30. Modularidad: comprensibilidad <ul><li>Antes dijimos que si si los módulos no obedecen a la lógica del dominio, no son legibles o no están bien documentados, entonces la descomposición es inútil y no permite la reusabilidad. </li></ul><ul><li>Cuando se dice que la descomposición de los módulos obedece a la lógica del dominio, se quiere decir que la mayoría de cada uno de módulos debe ser una representación natural de entidades o relaciones del dominio (por ejemplo: cuenta, beneficiario, oficina, control de riesgo, etc.). Decimos la mayoría: ya que habrá módulos que no modelizan entes del dominio (pertenecen al dominio de la aplicación exclusivamente: interfaz gráfico, sentencia SQL, etc.). </li></ul>
  31. 31. Modularidad: trazabilidad <ul><li>Se debe representar la continuidad entre los conceptos del proceso de desarrollo. </li></ul><ul><li>La regla de la trazabilidad indica que cada conjunto lógico de entidades y relaciones del dominio tiene su correlato modular . Esto facilita la extensibilidad y la reusabilidad. </li></ul><ul><li>Los métodos de Diseño orientado a facetas, orientados a aspectos o temas hacen énfasis en mejorar la trazabilidad de requisitos. </li></ul>Especificación de requisitos Análisis Diseño Programación
  32. 32. Modularidad: arquitectura en capas <ul><li>De todo lo anterior (coherencia, bajo acoplamiento, etc.) se deduce que gran parte de nuestras aplicaciones se descomponen en módulos que reflejan su especialización funcional: </li></ul><ul><ul><li>Interfaz con el usuario. </li></ul></ul><ul><ul><li>Implementación . Se aplican cálculos y algoritmos específicos al dominio. </li></ul></ul><ul><ul><li>Control . También implica conocimiento específico del dominio. Componentes que especifican el orden de las tareas y las condiciones de disparo (Si-entonces). Comprueban estados y errores. No tienen cálculos o algoritmos complejos. Por ejemplo, reglas de negocio del tipo: “Si el solicitante es cliente, entonces producir pedido; si no, solicitar registro de nuevo cliente”. </li></ul></ul><ul><ul><li>Almacenamiento y conectividad . Módulos responsables de la interacción con la base de datos y otras aplicaciones. </li></ul></ul>
  33. 33. Modularidad: arquitectura en tres capas <ul><li>En la práctica, sobre todo en aplicaciones que no son muy grandes, se suelen reunir en un módulo las clases de implementación y de control. </li></ul><ul><li>Un ejemplo es la arquitectura en tres capas, tan usual en aplicaciones Web: </li></ul><ul><ul><li>Presentación </li></ul></ul><ul><ul><li>Reglas de negocio </li></ul></ul><ul><ul><li>Acceso a datos (almacenamiento y conectividad) </li></ul></ul>
  34. 34. Jerarquía
  35. 35. Jerarquía: introducción <ul><li>Las dos formas más usuales de jerarquía de clases son : </li></ul><ul><ul><li>Jerarquía de tipos o herencia </li></ul></ul><ul><ul><li>Jerarquía de partes o agregación: </li></ul></ul><ul><ul><ul><li>Composición </li></ul></ul></ul><ul><ul><ul><li>Contenedor </li></ul></ul></ul><ul><li>La jerarquía por herencia supone un orden de abstracción/concreción, donde una excesiva cantidad de niveles (aprox. más de cuatro) hace difícil el mantenimiento. </li></ul><ul><li>La jerarquía de agregación. También el exceso de niveles produce confusión. </li></ul>Persona Alumno Profesor Coche Motor 1
  36. 36. Jerarquía: herencia y redefinición <ul><li>La herencia es una: </li></ul><ul><ul><li>Forma de abstracción. Primero nos centramos en el vehículo y después en sus subtipos (coche, autobus, etc.) </li></ul></ul><ul><ul><li>Forma de modularizar. </li></ul></ul><ul><li>Permite la redefinición de métodos. En la redefinición se mantiene el interfaz del método y cambia la implementación; esto es un ejemplo simple de polimorfismo (un interfaz y múltiples implementaciones). Tipos: </li></ul><ul><ul><li>Redefinición completa: no uso el servicio base </li></ul></ul><ul><ul><li>Redefinición parcial: uso el servicio de la clase base </li></ul></ul>CLASE PROFESOR (redefinición parcial) public void mostrar() { super.mostrar(); System.out.println( “Horas lectivas: &quot; + horas_lectivas); } CLASE EMPLEADO (redefinición completa) public void mostrar() { System.out.print( nombre + &quot;, &quot; ); System.out.println( salario_bruto); } empleado nombre salario_bruto mostrar() profesor horas_lectivas mostrar()
  37. 37. Jerarquía: herencia y polimorfismo <ul><li>Un nombre puede denotar instancias de muchas clases diferentes , siempre que estas clases hereden de una clase común. </li></ul><ul><li>Emplear el mismo interfaz con implementaciones diferentes </li></ul>empleado[] personal = new empleado[x]; personal[0] = new administrativo(...); personal[1] = new profesor(...); personal[0].mostrar(); personal[1].mostrar();
  38. 38. Jerarquía: herencia y ligadura dinámica <ul><li>Un ejemplo de polimorfismo en el que la llamada (ligadura) al método se resuelve en tiempo de ejecución. </li></ul><ul><li>Imaginemos un vector de figuras: </li></ul><ul><ul><li>figura vector[] = new figura[x]; </li></ul></ul><ul><li>Damos la opción al usuario de crear libremente el tipo de figura que quiera y el programa la almacena en el vector: </li></ul><ul><ul><li>vector[y] = new círculo(); </li></ul></ul><ul><ul><li>... </li></ul></ul><ul><ul><li>vector[y] = new rectángulo(); </li></ul></ul><ul><li>¿A qué método llama? vector[z].dibujar(); </li></ul><ul><li>Gracias a la ligadura dinámica el programa llama al objeto adecuado. </li></ul>rectángulo void dibujar() circulo void dibujar() figura void dibujar()
  39. 39. Jerarquía: herencia y clases abstractas <ul><li>En nuestro ejemplo de las figuras el programador no ha incluido la implementación del método obt_area () para la clase figura. Es lógico, podemos calcular el área de los rectángulos o de los círculos, pero no podemos calcular el área de un concepto tan abstracto como el de figura . </li></ul><ul><li>Esto no es raro en una clase madre, en muchas ocasiones las clases más elevadas en una jerarquía de herencia especifican un interfaz (declaración de función), sin definir una implementación. En nuestro ejemplo no se puede calcular el área de una figura. </li></ul><ul><li>Denominamos clases abstractas a aquellas que tienen o heredan un método abstracto, es decir, métodos declarados pero no implementados. No puede haber instancias de las clases abstractas. </li></ul><ul><li>En nuestro ejemplo la clase madre puede ser: </li></ul><ul><ul><ul><li>abstract class figura { </li></ul></ul></ul><ul><ul><ul><li>protected punto origen; </li></ul></ul></ul><ul><ul><ul><li>figura( punto origen) { </li></ul></ul></ul><ul><ul><ul><li>this.origen = origen; </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><ul><li>figura(int x, int y) { </li></ul></ul></ul><ul><ul><ul><li>origen = new punto(x,y); </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><ul><li>abstract double obt_area(); </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul>
  40. 40. Clases abstractas en diferentes lenguajes Eiffel deferred class Figura feature dibujar is deferred end ... Java abstract class Figura { abstract void dibujar(); ...} C++ class Figura { public: virtual void dibujar() = 0; ...
  41. 41. Jerarquía: agregación <ul><li>Encontrar clases agregadoras es: </li></ul><ul><ul><li>Forma de abstracción. Primero nos centramos en el Coche y después en sus componentes (motor, etc.). </li></ul></ul><ul><ul><li>Forma de modularizar. </li></ul></ul><ul><li>Tipos: </li></ul><ul><ul><li>Composición. La parte (Plan estratégico) desaparece cuando desaparece el todo (Empresa). Otro ejemplo: casa/cocina. </li></ul></ul><ul><ul><li>Contenedor. El componente (Ratón) no desaparece con el contenedor (Computadora). Otro ejemplo: cesta/manzanas. </li></ul></ul>
  42. 42. Ejemplos de agregación <ul><li>Un ejemplo de composición con la librería Swing para hacer applets (clase JApplet ). La parte (botones y etiquetas) desaparecen cuando desaparece el todo ( applet ): </li></ul><ul><ul><ul><li>public class mi_japplet extends JApplet { </li></ul></ul></ul><ul><ul><ul><li> /*** Creo los componentes ***/ </li></ul></ul></ul><ul><ul><ul><li> JLabel etiqueta_titulo = new JLabel(); </li></ul></ul></ul><ul><ul><ul><li> JButton boton1 = new JButton(); </li></ul></ul></ul><ul><ul><ul><li> JButton boton2 = new JButton(); </li></ul></ul></ul><ul><li>Un ejemplo de contenedor. El panel de contenidos que tiene el JApplet se llama contenedor . Debemos añadir ( add ) los botones y etiquetas a este panel para que aparezcan por pantalla: </li></ul><ul><ul><ul><li>private void jbInit() throws Exception { </li></ul></ul></ul><ul><ul><ul><li>Container contenedor = getContentPane(); </li></ul></ul></ul><ul><ul><ul><li>contenedor.setLayout( new FlowLayout() ); </li></ul></ul></ul><ul><ul><ul><li>/*** Añadir componentes al contenedor ***/ </li></ul></ul></ul><ul><ul><ul><li>contenedor.add (etiqueta_titulo); </li></ul></ul></ul><ul><ul><ul><li>contenedor.add (boton1); </li></ul></ul></ul><ul><ul><ul><li>contenedor.add (boton2); </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul>

×