Descargar la presentación
La descarga está en progreso. Por favor, espere
Publicada porRamón Benítez Pérez Modificado hace 10 años
1
Algoritmos y Programación III 9. Diseño micro y refactorización Carlos Fontela, 2006
2
Temario Diseño micro o de clases Cohesión y acoplamiento Diseño de interfaces Jerarquías Condiciones anormales Refactorización ¿Para qué? ¿Cuándo? Condiciones previas Problemas típicos que necesitan refactorización
3
Bases del diseño de clases Una buena arquitectura. Buenas prácticas de diseño y programación. Patrones de diseño. Eckel: “Un diseño termina cuando no se pueden extraer más cosas del mismo.” “Las tareas más habituales se deben poder hacer de una forma bien sencilla.”
4
Clases Cada clase con un propósito simple y claro: una clase por abstracción y una abstracción por clase. Separar las dependencias de una plataforma en una clase aparte.
5
Patologías en diseño de clases Clases con nombres verbales: No se supone que una clase hace algo, sino que provee un conjunto de servicios. Clases sin métodos. Clases que no introducen nuevos métodos ni los redefinen. Sólo heredan. Clases que se refieren a varias abstracciones: Se deberían dividir en varias.
6
Cohesión y acoplamiento Cohesión: Cada módulo haga una sola cosa simple. Acoplamiento: Independencia entre módulos. Asegurar bajo acoplamiento y alta cohesión en: Métodos Clases Paquetes Algunos patrones ayudan.
7
Interfaces de clases (I) Es lo que ve el cliente Más clara Más consistente Más simple Más intuitiva No quitar funcionalidad En Java: /** @deprecated */ “privatizar” lo más posible Pocos parámetros
8
Interfaces de clases (II) Implementar operaciones canónicas Comparable Serialización, toString() Clonación No necesariamente en la misma clase No incluir opciones en métodos que realizan acciones: Hacerlo en el constructor O en forma sucesiva: documento.establecerHoja(A4); documento.establecerColor(rojo); documento.imprimir();
9
Interfaces de clases (III) No hay problema si podemos modificar todo el código que depende de ellas Por eso, es mejor mantener el principio del mínimo privilegio Todo lo más privado que se pueda Publicar las interfaces sólo si es necesario
10
Atributos Atributos deberían mostrar sólo estado y los métodos sólo comportamiento No abusar de la herencia para expresar estado: El color de una figura es un atributo No crear clases para varones y mujeres Estado condicionado por los invariantes de clase: Se expresan como restricciones entre atributos Conviene separar atributos vinculados en una clase aparte que controle el cumplimiento de los invariantes Cuestiones de eficiencia nos pueden llevar a que no mantengamos siempre los invariantes de la clase
11
Métodos Ojo con métodos con grandes switch en los que se hace una cosa u otra en base al valor de un atributo: if (unaFigura.getClass() == Elipse.class) (Elipse)unaFigura.dibujar(); else if (unaFigura.getClass() == Poligono.class) (Poligono)unaFigura.dibujar(); Habría que analizar el uso de herencia y polimorfismo O sobrecarga
12
Jerarquías (I) Poner la mayor parte de los atributos y métodos lo más arriba que se pueda: para evitar luego definiciones duplicadas Si una porción de código se repite en muchas clases hermanas, habría que generar un método y ponerlo en la clase base Evitar generalizar todo lo que parezca generalizable de entrada Primero debemos resolver el problema que tenemos entre manos de la manera lo más simple posible
13
Jerarquías (II) Una nueva clase descendiente debe añadir o redefinir un método (modificar la interfaz) Si no, no es necesaria Riesgo de complicar la jerarquía sin un fin práctico. Las jerarquías deben ayudar a dominar la complejidad, no a complicarla Es más sencillo describir una jerarquía de lo general a lo particular Pero esto no siempre se aplica a la construcción: Jerarquía construida por demanda Generalizaciones que surgen al descubrir atributos o métodos en común en clases ya construidas Sí para clases adquiridas
14
Excepciones a la herencia (I) Aves como animales voladores. ¿Pingüinos, gallinas, etc.? Idiomas de Europa como indoeuropeos. ¿magiar, finés y turco? El uso de herencia con excepciones es una práctica cuestionable. Utilizar subclases para expresar las excepciones. Pero las clasificaciones con subclases no permiten excepciones por diferentes categorías. No voy a poder clasificar a las aves también como americanas y europeas sin caer en herencia repetida.
15
Excepciones a la herencia (II) Pocas soluciones en el terreno práctico Herencia múltiple, en los lenguajes que la manejan Interfaces cuando las excepciones se dan a nivel de métodos Caso de discusión: ¿La circunferencia es una elipse con un radio menos? ¿Cómo lo manejamos?
16
Condiciones anormales (I) Una excepción indica un error de ejecución Mala idea elevar una excepción si no hay error Por ejemplo, si en una búsqueda no se encontró el valor buscado Máxima: “Cuando todo falle, lance una excepción”
17
Condiciones anormales (II) “Un parámetro de error consume menos recursos” No nos guiemos por microeficiencias: privilegiar la robustez y la seguridad Las excepciones nos obligan a hacer algo con ellas: chequeo de condiciones lógicas puede evitarse, dando la impresión de que no ha habido un error cuando en verdad lo hay Máxima del diseño robusto: “Nunca se debe dar la impresión de que no pasó nada cuando algo ha fallado”
18
Condiciones anormales (III) Una implementación de clase debería venir con las excepciones que puede disparar Ponerlas en el mismo paquete Cuando se produce una excepción luego de capturar recursos, a veces debemos liberarlos El recolector de basura se va a ocupar de la memoria El resto los debe liberar el programador En el bloque finally Buena práctica: liberar en orden inverso a la adquisición
19
Diseño por contrato Invento de Meyer Hay un contrato entre implementador y cliente basado en: Invariantes de clase Precondiciones de métodos Postcondiciones de métodos Facilidad para pasar de diseño a implementación Se centra más en qué hacen las clases que en cómo se hace Implementado directamente en Eiffel
20
Refactorización “Refactoring” Mejorar el diseño de código ya escrito ¿Cómo? Modificar estructura interna Sin modificar funcionalidad externa Un poco como las optimizaciones Ejemplo muy simple… y trillado Eliminar código duplicado
21
Para qué Mejorar código, haciéndolo más comprensible Para modificaciones Para depuraciones Para optimizaciones Mantener alta la calidad del diseño Si no, se degrada A la larga, aumenta la productividad
22
Cuándo Antes de modificar código existente Siempre después de incorporar funcionalidad Antes de optimizar Durante depuraciones Durante revisiones de código Siempre, si se hace TDD o XP
23
Condiciones previas Riesgo alto Máxima: “Si funciona, no lo arregle” Un paso por vez Pruebas automatizadas Escribirlas antes de refactorizar Y correrlas luego de cada pequeño cambio
24
Problemas y refactorización “Bad smells in code” (malos olores), los llama Fowler Son indicadores de que algo está mal, y se solucionan con refactorizaciones Hay catálogos por todos lados También en “Piensa en Java”, de Eckel Veamos…
25
Cuestiones y soluciones (I) Código duplicado Extraer un método Extraer y llevar arriba en la jerarquía Extraer una clase, cuando no hay jerarquía en común Método largo Extraer métodos Nos podemos ayudar con los comentarios Y con partes condicionales y ciclos
26
Cuestiones y soluciones (II) Clase grande, con muchas responsabilidades Extraer clases Extraer subclases Lista de parámetros larga Crear clases para los parámetros Eliminar el parámetro y agregar una llamada a método
27
Cuestiones y soluciones (III) Cambios divergentes Separar las clases cuya necesidad de cambio tenga frecuencias distintas o provenga de necesidades diferentes “Shotgun surgery” Es lo opuesto a lo anterior, cuando cada cambio me obliga a tocar muchas clases Mover atributos o métodos para crear una única clase
28
Cuestiones y soluciones (IV) “Envidia de características” Cuando una clase se la pasa llamando a métodos de otras clases Poner los métodos en las clases que los usan Clases sin comportamiento Pueden provenir de refactorizaciones anteriores Pueden existir, pero no es bueno
29
Cuestiones y soluciones (V) Ifs y switchs abundantes Herencia y polimorfismo Patrones Estado (State) y Estrategia (Strategy) Otras soluciones de catálogo Jerarquías paralelas Juntar clases
30
Cuestiones y soluciones (VI) “Herencia especulativa” Colapsar la jerarquía Clases que son alternativas pero tienen interfaces diferentes Renombrar métodos y otras más complicadas Hay más Ver Fowler, con sus soluciones
31
¿Flexibilidad? La flexibilidad oscurece el código Y agrega complejidad En general, se flexibiliza uno u otro aspecto, según lo que se espera que cambie Es el enfoque de los Patrones de diseño
32
Caso I: extraer ancestro Sin problemas para los clientes: se siguen usando las clases descendientes
33
Caso II: extraer descendientes Hay que modificar clientes, haciendo una refactorización en pasos para más seguridad
34
Bibliografía Refactoring Martin Fowler Básicamente, un catálogo de refactorizaciones típicas Refactoring to Patterns Joshua Kerievsky Patrones de diseño como un objetivo de la refactorización
35
Resumen Las clases deben tener estado y comportamiento Mantener el principio de mínimo privilegio Nunca se debe dar la impresión de que no pasó nada cuando algo ha fallado Refactorizar para mejorar la calidad del código, no la funcionalidad Combinar refactorización y pruebas unitarias y de integración constantes
36
Qué sigue Concurrencia Aplicaciones distribuidas Integración de aplicaciones
37
Muchas Gracias. Carlos Fontela, 2006
Presentaciones similares
© 2025 SlidePlayer.es Inc.
All rights reserved.