domingo, 26 de julio de 2015

Examen POO Junio 2015 prMaternidad (Primera Parte)

Buenas gente. Ya estoy de nuevo por aquí, que recientemente uno de mis alumnos me ha pasado éste examen y yo, aburrido, he decidido hacerlo.
Os traigo los primeros 6.5 puntos porque estoy vago. Ya acabaré el resto otra tarde :)

El enunciado podéis descargarlo de aquí. De todos modos os lo pego por aquí por si queréis leerlo ;)

Se desea desarrollar una aplicación para la gestión de pacientes a los que atiende el servicio de maternidad de un hospital. Para ello, se creará un proyecto prMaternidad con las clases siguientes:
1) (0.25 ptos.) La clase MaternidadException se utilizará para tratar las diferentes situaciones excepcionales. Se trata de una excepción no comprobada. En general, se lanzará esta excepción si los parámetros de entrada de los métodos no contienen valores adecuados.
2) (2.25 ptos.) La clase Persona mantendrá información sobre un paciente ingresado en el área de maternidad del hospital. En concreto, su nombre (String), un código (int) que se considerará único y la habitación (int) asignada a ese paciente. La clase dispondrá de constructores y métodos necesarios para:
a. Construir un objeto de la clase dados los valores para las tres variables descritas anteriormente. Si el código proporcionado no es un número positivo mayor que cero o la habitación dada es negativa se debe lanzar una excepción de tipo MaternidadException informando de tal situación.
b. Obtener el nombre (String getNombre()), el código (int getCodigo()) y el número de habitación (int getHabitacion()).
c. La representación de una persona (String toString()) viene dada por su nombre, código y número de habitación separados por el carácter ‘:’.
Ej: García, Ana:1002:132
d. Dos objetos de la clase Persona son iguales si coinciden sus códigos, que recordemos que son únicos.
e. Los objetos de la clase Persona se ordenan de forma natural por código.
f. Se proporcionará una ordenación alternativa, que organice los objetos primero por nombre, ignorando mayúsculas y minúsculas, y, en caso de igualdad, por código. Esta ordenación deberá definirse en una clase aparte, llamada OrdAlt.
NOTAS PARA LA REALIZACIÓN DEL EJERCICIO:
 El ejercicio se almacenará en el directorio C:\POO. En caso de que no exista deberá crearse, y si ya existiese, deberá borrarse todo su contenido antes de comenzar.
 Al inicio del contenido de cada fichero deberá indicarse el nombre del alumno, titulación, grupo y código del equipo que está utilizando.
 La evaluación tendrá en cuenta la claridad de los algoritmos, del código y la correcta elección de las estructuras de datos, así como los criterios de diseño que favorezcan la reutilización.
 Los diferentes apartados tienen una determinada puntuación. Si un apartado no se sabe hacer, el alumno no debe pararse en él indefinidamente. Puede abordar otros.
 Está permitido:
o Consultar el API.
 No está permitido:
o Utilizar otra documentación electrónica o impresa.
o Intercambiar documentación con otros compañeros.
o Utilizar soportes de almacenamiento.
 Una vez terminado el ejercicio subir un fichero comprimido sólo con los ficheros .java que hayáis realizado a la tarea creada en el campus virtual para ello.
3) (4 ptos.) La clase Maternidad almacenará la información de los pacientes del servicio de maternidad en una estructura pacientes de tipo SortedMap<Persona, SortedSet <Persona>>, de tal manera que cada madre ingresada esté asociada al conjunto de bebés a los que ha dado a luz. La madre y los bebés suelen estar en la misma habitación, pero hay veces en qué ello no ocurre así. Por ejemplo, si alguno de los bebés debe ir a la incubadora (habitación con código 0).
La clase debe proporcionar los siguientes constructores y métodos públicos:
a. El constructor Maternidad() crea la estructura de datos. Se debe tener en cuenta que queremos ordenar las madres por nombre (orden alternativo mencionado anteriormente). Los bebés asociados a cada madre se ordenarán por código (orden natural).
El constructor Maternidad(String)recibe un nombre de fichero y, tras crear la estructura de datos, añade toda la información que contiene el fichero (ver apartados siguientes).
b. Los métodos addPacientesFichero(String) y addPacientes(Scanner) añaden información sobre pacientes a la estructura de datos. El primero lee la información de un fichero. El segundo desde el flujo de entrada proporcionado. Se supondrá que la información sobre cada madre y sus bebés se encuentra en una línea de texto, donde el carácter ‘#’ separa la información de distintas personas. Para cada persona, sus datos particulares se separan con el carácter ‘:’. Por ejemplo, la siguiente línea indica que la persona Ana García es madre de dos niños, Pedro y Nuria.
García,Ana:1002:132#López,Pedro:1034:132#López,Nuria:1036:0
Cualquier error de formato detectado (falta algún dato personal, o bien el dato no es del tipo correcto), provocará el lanzamiento de una excepción del tipo MaternidadException.
Se proporciona el fichero de datos pacientes.txt para probar el correcto funcionamiento de la solución implementada.
c. El método addMadreBebes(Persona madre, Collection<Persona> bebes) registra la madre y sus bebes en el servicio de maternidad. Nótese que la colección bebes puede estar vacía, lo que indica que dicha madre aún no ha dado a luz. Si la madre ya estuviese registrada se añadirán los bebés indicados por el segundo parámetro al conjunto de bebés que ya tenía previamente.
d. Se ha de redefinir el método String toString(). La representación de los objetos de la clase muestra toda la información contenida en la estructura de datos. El formato que se ha de utilizar es el que aparece en el fichero pacientes.txt. Es decir, en cada línea la información de una madre y sus bebés.
e. Los métodos escribirFichero(String) y escribir(PrintWriter) guardan la información de la estructura de datos en el fichero o en el flujo de salida dado respectivamente.
f. El método double mediaBebes() calcula el número medio de bebés por madre que están registrados en el sistema. Aquellas madres que no tienen hijos asociados no se tienen en cuenta en el cómputo.
g. El método int encontrarMadre(int codigoBebe) devuelve el número de habitación de aquella persona que es madre del bebé cuyo código se pasa como parámetro. En caso de no encontrarse la madre, se debe lanzar una excepción de tipo MaternidadException informando de tal situación.
Igualmente os aconsejo que lo descarguéis. Se verá mejor que aquí.
Aquí os dejo también las clases terminadas, pero no os limiteis a verlas. Intentad hacerlo vosotros y luego comparáis ;)
MaternidadException, Persona, OrdAlt, Maternidad.
Aquí os dejo pegado el código ;)
MaternidadException:
public class MaternidadException extends Exception {
    public MaternidadException() {
        super();
    }
    public MaternidadException(String e) {
        super(e);
    }
}

Persona:
public class Persona {
    private String nombre;
    private int codigo;
    private int habitacion;
    
    public Persona(String nombre, int codigo, int habitacion) throws MaternidadException{
        if(codigo <1 || habitacion<0)
            throw new MaternidadException("Codigo o habitacion incorrectos.");
        this.nombre = nombre;
        this.codigo = codigo;
        this.habitacion = habitacion;
    }
    
    public String getNombre() {
        return this.nombre;
    }
    public int getCodigo() {
        return this.codigo;
    }
    public int getHabitacion() {
        return this.habitacion;
    }
    
    public String toString() {
        return this.nombre+":"+this.codigo+":"+this.habitacion;
    }
    
    public boolean equals(Persona p) {
        return this.codigo==p.getCodigo();
    }
    public int compareTo(Persona p) {
        int cod = p.getCodigo();
        if(this.codigo<cod)
            return -1;
        else if(this.codigo>cod)
            return 1;
        else
            return 0;
    }
    
}

OrdAlt:
public class OrdAlt extends Persona{
    public OrdAlt(String nombre, int codigo, int habitacion) throws MaternidadException{
        super(nombre, codigo, habitacion);
    }
    
    public int compareTo(OrdAlt p) {
        String nombre1 = this.getNombre().toLowerCase();
        String nombre2 = p.getNombre().toLowerCase();
        int c = nombre1.compareTo(nombre2);
        
        if(c!=0)
            return c;
        
        /* Copiado tal cual de Persona*/
        int cod = p.getCodigo();
        if(this.getCodigo()<cod)
            return -1;
        else if(this.getCodigo()>cod)
            return 1;
        else
            return 0;
        
    }
}

Maternidad:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.Scanner;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author NikNitro
 */
public class Maternidad {
    private final int incubadora = 0;
    private SortedMap<Persona, SortedSet<Persona>> pacientes;
    
    public Maternidad() {
        pacientes = new TreeMap<>();
    }
    public Maternidad(String std) {
        pacientes = new TreeMap<>();
        addPacientesFichero(std);
        
    }
    
    public void addPacientesFichero(String std){
        File f = new File(std);
        try {
            Scanner sc = new Scanner(f);
            sc.useDelimiter("\n");
            addPacientes(sc);
        } catch (FileNotFoundException ex) {
            Logger.getLogger(Maternidad.class.getName()).log(Level.SEVERE, null, ex);
        } catch (MaternidadException e ) {
            System.err.printf("Existe algún error con el archivo dado");
        } 
    }
    
    public void addPacientes(Scanner sc) throws MaternidadException{
        String linea, persona, nombre;
        int codigo, habitacion;
        boolean esMadre = true;
        OrdAlt madre= null;
        Persona bebe;
        Collection<Persona> bebes = null;

        while(sc.hasNext()) {   //Vemos cada línea
            linea =sc.next();
            Scanner separador = new Scanner(linea);
            separador.useDelimiter("#");
            
            while(separador.hasNext()) {    //Vemos cada persona en una línea
                try{
                    persona = separador.next();
                    Scanner dosPuntos = new Scanner(persona);   //Vemos los datos de cada persona
                    dosPuntos.useDelimiter(":");
                    nombre = dosPuntos.next();
                    codigo = Integer.parseInt(dosPuntos.next());
                    habitacion = Integer.parseInt(dosPuntos.next());
                    if(esMadre) {
                        madre = new OrdAlt(nombre, codigo, habitacion);
                        esMadre = false;
                        bebes = new TreeSet<>();
                    } else {
                        bebe = new Persona(nombre, codigo, habitacion);
                        bebes.add(bebe);
                        
                    }
                } catch(NumberFormatException | MaternidadException e) {
                    throw new MaternidadException();
                }
            }
            //Aquí ya hemos rellenado a la madre y el treeSet con una línea.
            addMadreBebes(madre, bebes);
            esMadre = true;
        }
    }
    
    public void addMadreBebes(Persona madre, Collection<Persona> bebes) {
        if(pacientes.containsKey(madre))
            
                //Es la forma nueva de java 8. La antigua sería "for(Persona b : bebes)"
            bebes.stream().forEach((b) -> {
                pacientes.get(madre).add(b);
            });
        else {
            SortedSet bebe = new TreeSet<>();
            bebes.stream().forEach((b) -> {
               bebe.add(b);
            });
            pacientes.put(madre, bebe);
        }
    }
    
    @Override
    public String toString() {
        String std="";
        for (Persona p : pacientes.keySet()) {
            std = std + p + "#";
            for(Persona b : pacientes.get(p)) {
                std = std + b + "#";
            }
            std = std+"\n";
        }
        return std;
    }
    
    public void escribirFichero(String s) {
        File f = new File(s);
        PrintWriter p;
        try {
            p = new PrintWriter(f);
            escribir(p);
        } catch (FileNotFoundException ex) {
            Logger.getLogger(Maternidad.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    public void escribir(PrintWriter p) {
        p.append(this.toString());
    }
    
    public double mediaBebes() {
        double numMadres = 0, numBebes = 0;
        for(Persona p : pacientes.keySet()) {
            SortedSet bebes = pacientes.get(p);
            if(bebes.size()>0) {
                numMadres++;
                numBebes += bebes.size();
            }
                
        }
        return numBebes/numMadres;
    }
    
    public int encontrarMadre(int codigoBebe) throws MaternidadException{
        for(Persona m : pacientes.keySet()) 
            for(Persona b : pacientes.get(m)) {
                 if(b.getCodigo()== codigoBebe)
                     return m.getHabitacion();
            }
            
        throw new MaternidadException("Madre no encontrada");
        
    }
}

Os aviso de que el código aún no está probado, por lo que si veis cualquier cosilla que de error o que no cuadre, por favor avisadme para que lo arregle.

Saludos y gracias por visitarme;)