MIT OpenCourseWare


6.170 Curso práctico en ingeniería del software.

Página principal
¿Qué es OCW?
Ayuda
Feedback
Preguntas frecuentes
Glosario
 
 
Página principal del curso
Programa
Calendario
Material de clase
Trabajos
Exámenes
  Lecturas obligatorias
  Otras fuentes
  Prácticas
  Grupos/Clases de repaso
  Herramientas
  Proyectos

   MIT

   
 

Trabajos

Ejercicio 3: diseño de un tipo abstracto de datos

Plazo de entrega: 4ª semana

Hoja E3

Le aconsejamos que todos los problemas antes de ponerse a trabajar.

Introducción

En este ejercicio, diseñará e implementará un tipo abstracto. Para diseñar un tipo abstracto hay que determinar primero su utilidad y su comportamiento, es decir, hay que escribir una especificación. Materializar un tipo abstracto supone escoger una representación y algoritmos, y plasmarlos en código. El diseño es el interés principal de este ejercicio, por lo que tiene que dedicarle una cantidad de tiempo considerable. Para comprobar que su diseño es factible, utilizará un tipo de datos diseñado por usted para crear un programa sencillo que encuentre direcciones mediante un mapa del metro de Boston que le facilitaremos.

Grafos

El tipo abstracto que diseñará es un multi-grafo dirigido y etiquetado. Un grafo es simplemente un conjunto de nodos con aristas entre ellos. Cada arista conecta un nodo con otro. Puede haber nodos sin aristas pero no aristas sin nodos. Un nodo puede estar conectado a él mismo. Puede haber cero, una o más aristas entre un par de nodos. Cada arista tiene una etiqueta; aristas distintas pueden tener la misma etiqueta.

Aquí tiene algunos ejemplos de aplicaciones con multi-grafos dirigidos y etiquetados.

  • Un compilador puede representar el flujo de control de un programa como un grafo cuyos nodos son puntos en el programa y cuyas aristas son enunciados del programa. El grafo se utilizaría para hacer análisis, como la propagación del valor de las constantes, y para llevar a cabo transformaciones, tales como extraer un enunciado fuera de un bucle.
  • Una herramienta para el diseño de una página web puede representar una página web como un grafo cuyos nodos son documentos y cuyas aristas son enlaces. La herramienta puede examinar el sitio para comprobar la conectividad, encontrar enlaces que no funcionan, actualizar todos los documentos cuando uno de ellos se ha movido, y otros temas de esta índole.
  • Una herramienta para el diseño de un plan de estudios puede utilizar un grafo para mostrar qué condiciones previas se establecen para poder cursar una asignatura, para encontrar imperfecciones y determinar programas de estudio viables.
  • Un programa que genere direcciones mientras conduce puede usar un grafo para representar un callejero y calcular el camino más corto para encontrar direcciones de un punto a otro.
  • Un compilador Java™ puede utilizar un grafo para representar dependencias entre los ficheros del código fuente, y para determinar un orden de compilación aceptable.

El tipo que usted diseñe se utilizará para encontrar direcciones en el metro de Boston, los nodos representarán las estaciones y las aristas representarán los segmentos de las vías. Se aconseja que el diseño y la implementación sean polimórficos, con lo cual es mejor utilizar un tipo de nodo genérico y que sea posible utilizar el diseño y la implementación del grafo en aplicaciones distintas.


La implementación del grafo debe ser eficaz, es decir, debería funcionar razonablemente con grafos de tamaño medio: los que tienen miles (pero no millones) de nodos y aristas. No presuponga que el grafo estará disperso (esto es, que contenga muy pocas aristas en comparación al número de nodos) o denso (esto es, con la mayoría de los pares de nodos conectados).

Ideas

Para darle una idea del tipo de puntos que debería tener en cuenta en su diseño, he aquí algunas cuestiones que tal vez le interese examinar. En general, no tienen respuestas sencillas. Tendrá que sopesarlas con cuidado y pensar detenidamente en cómo las decisiones que tome interferirán unas con otras.
  • ¿será el grafo mutable o inmutable? ¿será posible cambiar la etiqueta de una arista?
  • ¿permitirá el grafo aristas sin etiquetas?
  • ¿serán las etiquetas de la arista cadenas u objetos genéricos? si son objetos, ¿será correcto utilizar un nodo o una arista como etiqueta?¿o incluso un grafo?
  • ¿serán los nodos necesarios únicamente para satisfacer la interfaz de java.lang.Object? o ¿diseñará una interfaz Java™ para los nodos?
  • ¿se implementará el grafo como una clase única o habrá una interfaz de Java™ distinta para la especificación del grafo y una clase para la implementación?
  • ¿serán las aristas objetos por derecho propio? ¿estarán visibles para un cliente de tipo abstracto?
  • ¿será posible encontrar el sucesor de un nodo únicamente desde el nodo o será necesario también el gráfico? ¿puede un nodo pertenecer a grafos múltiples?
  • ¿qué clase de iteradores proporcionará el tipo?
  • ¿deberían incluirse las operaciones de búsqueda de ruta como métodos del grafo, o deberían implementarse en código cliente encima del grafo?
  • ¿facilitará el tipo algunas vistas, como el conjunto de vistas devueltas por el método entrySet de Java.util.Map?
  • ¿implementará el tipo algunas de las interfaces de la colección standard de Java™?
  • ¿utilizará el tipo algunas de las colecciones standard de Java™ en su implementación?

Problema 1: especificación de un grafo (60 puntos)

Diseñe un tipo de datos abstracto para un grafo dirigido y etiquetado. Le aconsejamos que guarde su trabajo de diseño en uno o más ficheros distintos del propio código fuente e incluya al menos los siguientes elementos:
  1. Un breve párrafo que exprese una visión general de qué clases o interfaces son visibles a los clientes del grafo y qué papel desempeñan, así como un diagrama de dependencia de módulos que muestre las relaciones entre ellos.
  2. Un comentario sobre la complejidad computacional del grafo: diga qué métodos espera que sean computacionalmente intensivos y denos una aproximación de su coste asintótico y de las necesidades de espacio. Por ejemplo, puede decir (de manera bastante inverosímil) que addNode será el método más costoso, que, a medida de que el grafo va creciendo, su coste debería aumentar como máximo cuatro veces con el tamaño del grafo y que la memoria que se necesita para representar el grafo aumentará de forma exponencial con el número de aristas.
  3. Para cada clase o interfaz público:
    • un párrafo general en el que explique de manera resumida qué objetos están representados por esa clase o interfaz, y si son o no mutables;
    • una especificación de cada método.
  4. Un breve listado del diseño preliminar (no más de media página), como puntos separados, una variedad de características alternativas de diseño que usted tuvo en cuenta pero que al final rechazó, motivando el porqué del rechazo.

Problema 2: implementación de un grafo (20 puntos)

Implemente el grafo y ensaye su implementación con JUnit.

Debería entregar:

  1. Una breve visión global de la representación que usted escogió, con un breve fundamento que defienda la suya en comparación con otra distinta (aunque plausible).
  2. Un diagrama de dependencia de módulos que muestre las clases y las interfaces que forman parte de su implementación y la relación que mantienen entre ellas.
  3. El código fuente debe estar comentado detalladamente.
  4. Un código para sus casos de prueba.
  5. Un enunciado que indique si su código pasa o no todos los tests. Asumiremos que el código falla si no dice nada.

Para este ejercicio bastará con un pequeño conjunto de casos de prueba. En el próximo ejercicio, volverá al código y lo examinará más detenidamente. Aquí, la prueba servirá para que se familiarice con JUnit y para eliminar errores importantes que le impedirían acabar este ejercicio.

Problema 3: utilización del grafo (20 puntos)

Cree un programa que genere direcciones para el sistema del metro de Boston. La idea es que se introduzcan dos nombres de estaciones en la línea de comandos y se generen los pasos que deben adoptarse.

Basta con una sencilla búsqueda a lo ancho. No se preocupe por controlar los tipos de complicaciones que un programa real tendría que controlar (como seleccionar un tren de la línea verde en Park Street y juntar todos los pasos en trayectos de líneas individuales).
Hemos escrito algún código que analiza el fichero que describe el sistema del metro de Boston. Este fichero bostonmetro.txt debería introducirse en el programa. El código en cuestión se encuentra en MetroMapParser.java. Le aconsejamos que modifique este fichero, insertando llamadas a los métodos de grafo TAD. Dependiendo de cómo haya diseñado su TAD, estas llamadas serán diferentes. Por ejemplo, si ha creado un grafo inmutable, tendría que haber capturado toda la información del fichero antes de crear el grafo. Sin embargo, si ha creado un grafo mutable, debería ser capaz de aumentarlo de forma incremental a medida de que el fichero es analizado. En cualquier caso, tendría que leer detenidamente el código del parser (analizador), y facilitar una documentación clara en la que explique las modificaciones que está llevando a cabo.

Debería entregar:

  1. El código fuente comentado con detalle.
  2. Muestras de salida para algunos casos de prueba.

Código facilitado

Le hemos proporcionado las siguientes clases en código fuente:

<MetroMapParser.java>
<BadFileException.java>

Cómo empezar

Asegúrese de que antes de comenzar a desarrollar la programación ha seguido las instrucciones concernientes al directorio de instalación y al manejo de Java. del menú Herramientas.

Cree un directorio ex3 y copie en él los ficheros que se le han proporcionado:

mkdir ~/6.170/ex3
cp -p /mit/6.170/www/psets/ex3/ex3-spec/* ~/6.170/ex3

Consejos

Consulte los consejos y directrices sobre los boletines de ejercicios.

Tal vez el método Integer.parseInt(String s)le sea útil para la conversión de cadenas a números enteros.

Aunque por lo general no es aconsejable empezar a escribir código antes de haber realizado un análisis profundo, a veces tiene sentido trabajar de forma incremental, intercalando diseño y código. Una vez que tenga un borrador de su especificación, quizás desee escribir algún tipo de código experimental, lo que le serviría para darse cuenta de la poca dificultad que tiene el implementar los métodos que ha especificado. Puede que incluso quiera comenzar por el final, y escribir el código que utilice el tipo diseñado por usted, de modo que pueda estar seguro de que los métodos que proporciona serán suficientes.

Esta estrategia puede salir mal y degenerar en una escritura sin sentido, dejándole con un montón de código de baja calidad y una especificación falta de coherencia. Para evitar esto, tenga presente dos cosas. Primero, debe estar dispuesto a empezar de nuevo: un código experimental no es experimental si no está preparado para desecharlo. Segundo, cuando empiece a escribir código, debe tener una idea muy clara de lo que está intentando implementar. No tiene sentido empezar a codificar una especificación que es imprecisa y que olvida detalles cruciales. Esto no significa que su especificación deba estar terminada y pulida, pero sí que no es aconsejable comenzar a codificar un método hasta por lo menos tener escrita su propia especificación. Tercero, debe escribir la especificación de un método y no simplemente imaginarla; es muy fácil engañarse a sí mismo. Intente escribirla en papel y reflexionar sobre ella antes de empezar cualquier codificación. Sentarse delante de un editor, escribir alguna especificación en forma de comentarios y empezar a codificar en torno a estos, resulta tentador, aunque suele ser poco eficaz.

Pida ayuda a su monitor de prácticas cuando sea necesario. Entregue su especificación en las horas de consulta antes de asistir a las prácticas y recabe alguna opinión o comentario sobre su estilo y diseño. Gracias a ello es probable que ahorre mucho tiempo.


Recuerde el consejo de Hoare de la Clase 1.

Erratas

El fichero bostonmetro.txt del Ejercicio 3 tiene un error. La línea

   41 Copley GreenB 51 34 GreenC 51 34 GreenD 51 34 GreenE 54 34

debería leerse

   41 Copley GreenB 51 34 GreenC 51 34 GreenD 51 34 GreenE 53 34

El error acaba la línea de llegada GreenE antes de tiempo en Prudential.
Le agradecemos a Ben Brown que nos haya avisado de esto.

Preguntas y Respuestas

Esta sección enumerará las aclaraciones y respuestas a preguntas frecuentes. Intentaremos mantenerla lo más actualizada posible, por lo que le sugerimos que consulte este apartado en primer lugar (después de haber repasado detenidamente la hoja) ante cualquier duda que le surja.

Volver arriba

Massachusetts Institute of Technology © 2003 MIT | Información Jurídica | Privacidad
Todo uso del sitio de MIT OpenCourseWare y sus materiales de curso queda sujeto a las condiciones y términos de uso detallados
en la sección sobre Información Jurídica
Copyright © 2003 Portal Universia S.A. Todos los derechos reservados
(Avda. de Cantabria s/n - Edif. Arrecife, planta 00.28660 Boadilla del Monte) - Madrid. España.
Contacta con nosotros: Usuarios | Empresas-Instituciones-Medios comunicación
Código Ético | Aviso Legal | Política de confidencialidad | Quiénes somos: Sala de Prensa