FUNDAMENTOS DE PROGRAMACIÓN PRÁCTICA 4: DISEÑO DE TIPOS Curso: 2010/11 Versión: 1.0.1 SOLUCIONES Ejercicios 1, 2 y 3 Definición de interfaces Tipo Punto public interface Punto extends Copiable<Punto>, Comparable<Punto>{ public Double getX(); public Double getY(); public void setX(Double x1); public void setY(Double y1); } Tipo Circulo public interface Circulo extends Comparable<Circulo>,Copiable<Circulo> { public Double getRadio(); public Punto getCentro(); public void setRadio(Double r); public void setCentro(Punto p); public Double getArea(); public Double getLongitud(); } Tipo Persona public interface Persona extends Comparable<Persona>, Copiable<Persona> { String getNombre(); String getApellidos() ; String getDNI() ; Integer getEdad(); Double getEstatura(); Character getSexo(); void setEdad(Integer e); void setEstatura(Double e); void setSexo(Character s); } Implementación de las clases con los esquemas propuestos Implementación de Punto public class PuntoImpl implements Punto { private Double x; private Double y; public PuntoImpl (Double x1, Double y1) { if(x1==null || y1 == null){ throw new IllegalArgumentException( "Algún parámetro es null"); } Práctica 4: Diseño de tipos x=x1; y=y1; } public Double getX() { return x; } public Double getY() { return y; } public void setX(Double x1) { if(x1==null){ throw new IllegalArgumentException( "Algún parámetro es null"); } x=x1; } public void setY(Double y1) { if(y1 == null){ throw new IllegalArgumentException( "Algún parámetro es null"); } y=y1; } public boolean equals (Object o){ boolean res = false; if(o instanceof Punto){ Punto p = (Punto) o; res = getX().equals(p.getX()) && getY().equals(p.getY()); } return res; } public String toString() { String s="("+getX()+","+ getY()+")"; return s; } public int hashCode(){ return getX().hashCode() * 31 + getY().hashCode(); } public int compareTo(Punto p){ int cmp = getX().compareTo(p.getX()); if(cmp == 0){ cmp = getY().compareTo(p.getY()); } return cmp; } public Punto clone() { Punto copia = null; try { copia = (Punto) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return copia; } } Implementación de Circulo public class CirculoImpl implements Circulo { private Double radio; 2 Práctica 4: Diseño de tipos private Punto centro; public CirculoImpl(Double r, Punto p){ if(r==null || p == null || r <= 0){ throw new IllegalArgumentException( "Algún parámetro es incorrecto"); } radio = r; centro = p; } public Double getRadio(){ return radio; } public Punto getCentro(){ return centro; } public void setRadio(Double r){ radio = r; } public void setCentro(Punto p){ centro = p; } public Double getArea(){ Double res = Math.PI * Math.pow(radio, 2); return res; } public Double getLongitud(){ return 2 * Math.PI * radio; } public Circulo clone() { Circulo copia = null; try { copia = (Circulo) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return copia; } public int compareTo(Circulo e) { int cmp = this.getRadio().compareTo(e.getRadio()); if (cmp == 0) { cmp = this.getCentro().compareTo(e.getCentro()); } return cmp; } public String toString() { return "Radio : " + radio + getCentro(); } public int hashCode() { final int prime = 31; int result = 1; result = prime * result + getCentro().hashCode(); result = prime * result + getRadio().hashCode(); return result; } public boolean equals(Object obj) { boolean res = false; if (obj instanceof Circulo){ Circulo other = (Circulo) obj; res = getCentro().equals(other.getCentro())&& getRadio().equals(other.getRadio()); 3 Práctica 4: Diseño de tipos } return res; } } Implementación de Persona public class PersonaImpl implements Persona { private String nombre; private String apellidos ; private String dni ; private Integer edad; private Double estatura; private Character sexo; public PersonaImpl(String nombre, String apellidos, String dni, Integer edad, Double estatura, Character sexo) { super(); if(nombre==null || apellidos == null || dni == null || edad == null || estatura == null || sexo == null || estatura <= 0.0 || edad < 0){ throw new IllegalArgumentException( "Algún parámetro es inapropiado"); } this.nombre = nombre; this.apellidos = apellidos; this.dni = dni; this.edad = edad; this.estatura = estatura; this.sexo = sexo; } public Integer getEdad() { return edad; } public void setEdad(Integer edad) { if( edad == null || edad < 0){ throw new IllegalArgumentException( "Algún parámetro es inapropiado"); } this.edad = edad; } public String getNombre() { return nombre; } public String getApellidos() { return apellidos; } public String getDNI() { return dni; } public Character getSexo() { return sexo; } public Double getEstatura() { return estatura; } public void setEstatura(Double estatura) { if(estatura == null || estatura <= 0.0){ throw new IllegalArgumentException( "Algún parámetro es inapropiado"); } 4 Práctica 4: Diseño de tipos this.estatura = estatura; } public void setSexo(Character sexo) { this.sexo = sexo; } public Persona clone() { Persona copia = null; try { copia = (Persona) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return copia; } public int compareTo(Persona e) { int cmp = this.getApellidos().compareTo(e.getApellidos()); if (cmp == 0) { cmp = this.getNombre().compareTo(e.getNombre()); } if (cmp == 0) { cmp = this.getDNI().compareTo(e.getDNI()); } return cmp; } public String toString() { return "" + nombre +", " + apellidos + " (" + dni + ")"; } public int hashCode() { final int prime = 31; int result = 1; result = prime * result + apellidos.hashCode(); result = prime * result + dni.hashCode(); result = prime * result + nombre.hashCode(); return result; } public boolean equals(Object obj) { boolean res = false; if (obj instanceof PersonaImpl){ Persona other = (Persona) obj; res = getApellidos().equals(other.getApellidos()) && getDNI().equals(other.getDNI()) && getNombre().equals(other.getNombre()); } return res; } } Implementación de las clases con el generador de código de Eclipse Obsérvese que el generador automático de Eclipse utiliza esquemas y criterios que pueden no coincidir con nuestros diseños. En concreto, 1. En los constructores no se gestionan excepciones; en nuestro código sí, por ejemplo no admitir null en los atributos. 2. Los métodos get y set los nombra get/set, la inicial del atributo en mayúscula y el resto de caracteres en minúscula; esto fallaría en el caso del método getDNI de nuestra interfaz. 3. En el método toString su formato estándar es NombreClase : nombre atributo valor … 5 Práctica 4: Diseño de tipos 4. El método equals solo trabaja con los de la misma implementación y no considerando la misma interfaz como en nuestro esquema. El método sí gestiona adecuadamente los atributos que pudiesen estar a null en el objeto a comparar. 5. El método hashCode gestiona adecuadamente los atributos que pudiesen estar a null en el objeto. Implementación de Punto usando el generador de código public class PuntoImpl2 implements Punto { private Double x; private Double y; public PuntoImpl2(Double x, Double y) { super(); this.x = x; this.y = y; } public Double getX() { return x; } public void setX(Double x) { this.x = x; } public Double getY() { return y; } public void setY(Double y) { this.y = y; } public String toString() { return "PuntoImpl2 [x=" + x + ", y=" + y + "]"; } public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((x == null) ? 0 : x.hashCode()); result = prime * result + ((y == null) ? 0 : y.hashCode()); return result; } public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof PuntoImpl2)) return false; PuntoImpl2 other = (PuntoImpl2) obj; if (x == null) { if (other.x != null) return false; } else if (!x.equals(other.x)) return false; if (y == null) { if (other.y != null) return false; } else if (!y.equals(other.y)) return false; return true; } 6 Práctica 4: Diseño de tipos public int compareTo(Punto e) { int cmp = this.getX().compareTo(e.getX()); if (cmp == 0) { cmp = this.getY().compareTo(e.getY()); } return cmp; } public Punto clone(){ Punto copia=null; try{ copia=(Punto)super.clone(); }catch(CloneNotSupportedException e){e.printStackTrace();} return copia; } } Implementación de Circulo usando el generador de código public class CirculoImpl2 implements Circulo { private static final Double PI = new Double(3.1416); private Double radio; private Punto centro; public CirculoImpl2(Double r, Punto p){ if(r==null || p == null || r <= 0){ throw new IllegalArgumentException( "Algún parámetro es incorrecto"); } radio = r; centro = p; } public Double getRadio(){ return radio; } public Punto getCentro(){ return centro; } public void setRadio(Double r){ radio = r; } public void setCentro(Punto p){ centro = p; } public Double getArea(){ Double res = PI * Math.pow(radio, 2); return res; } public Double getLongitud(){ return 2 * PI * radio; } public Circulo clone() { Circulo copia = null; try { copia = (Circulo) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return copia; } public int compareTo(Circulo e) { int cmp = this.getRadio().compareTo(e.getRadio()); 7 Práctica 4: Diseño de tipos if (cmp == 0) { cmp = this.getCentro().compareTo(e.getCentro()); } return cmp; } public String toString() { return "CirculoImpl [radio="+radio+",centro="+centro+"]"; } public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((centro == null) ? 0 : centro.hashCode()); result = prime * result + ((radio == null) ? 0 : radio.hashCode()); return result; } public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof CirculoImpl2)) return false; CirculoImpl2 other = (CirculoImpl2) obj; if (centro == null) { if (other.centro != null) return false; } else if (!centro.equals(other.centro)) return false; if (radio == null) { if (other.radio != null) return false; } else if (!radio.equals(other.radio)) return false; return true; } } Implementación de Persona usando el generador de código public class PersonaImpl2 implements Persona { private String nombre; private String apellidos ; private String dni ; private Integer edad; private Double estatura; private Character sexo; public PersonaImpl2(String nombre, String apellidos, String dni, Integer edad, Double estatura, Character sexo) { super(); this.nombre = nombre; this.apellidos = apellidos; this.dni = dni; this.edad = edad; this.estatura = estatura; this.sexo = sexo; } public Integer getEdad() { 8 Práctica 4: Diseño de tipos return edad; } public void setEdad(Integer edad) { if( edad == null || edad < 0){ throw new IllegalArgumentException( "Algún parámetro es inapropiado"); } this.edad = edad; } public String getNombre() { return nombre; } public String getApellidos() { return apellidos; } public Character getSexo() { return sexo; } public String getDNI() { return dni; } public Double getEstatura() { return estatura; } public void setEstatura(Double estatura) { if(estatura == null || estatura <= 0.0){ throw new IllegalArgumentException( "Algún parámetro es inapropiado"); } this.estatura = estatura; } public void setSexo(Character sexo) { this.sexo = sexo; } public Persona clone() { Persona copia = null; try { copia = (Persona) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return copia; } public int compareTo(Persona e) { int cmp = this.getApellidos().compareTo(e.getApellidos()); if (cmp == 0) { cmp = this.getNombre().compareTo(e.getNombre()); } if (cmp == 0) { cmp = this.getDNI().compareTo(e.getDNI()); } return cmp; } public String toString() { return "PersonaImpl2 [nombre=" + nombre + ", apellidos=" + apellidos + ", dni=" + dni + "]"; } public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((apellidos == null) ? 0 : 9 Práctica 4: Diseño de tipos apellidos.hashCode()); result = prime * result + ((dni == null) ? 0 : dni.hashCode()); result = prime * result + ((nombre == null) ? 0 : nombre.hashCode()); return result; } public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof PersonaImpl2)) return false; PersonaImpl2 other = (PersonaImpl2) obj; if (apellidos == null) { if (other.apellidos != null) return false; } else if (!apellidos.equals(other.apellidos)) return false; if (dni == null) { if (other.dni != null) return false; } else if (!dni.equals(other.dni)) return false; if (nombre == null) { if (other.nombre != null) return false; } else if (!nombre.equals(other.nombre)) return false; return true; } } Ejercicio 4 Tipo Racional public interface Racional extends Comparable<Racional>, Copiable<Racional> { Integer getNumerador(); Integer getDenominador(); Double getValorReal(); void setNumerador(Integer a); void setDenominador(Integer a); void suma(Racional r); void resta(Racional r); void multiplica(Racional r); void divide(Racional r); void invierte(); } Implementación de Racional public class RacionalImpl implements Racional { private Integer numerador; private Integer denominador; public RacionalImpl() { numerador = 1; 10 Práctica 4: Diseño de tipos denominador = 1; } public RacionalImpl(Integer a) { if( a == null) throw new IllegalArgumentException( "Parametro null"); numerador = a; denominador = 1; } public RacionalImpl(Integer a, Integer b) { if( a == null || b == null || b == 0 ) throw new IllegalArgumentException( "Parametros null o el divisor es cero"); if (b <0){ numerador = -a; denominador = -b; } else { numerador = a; denominador = b; } } public Integer getNumerador(){ return numerador; } public Integer getDenominador(){ return denominador; } public Double getValorReal(){ return ((double)getNumerador())/getDenominador(); } public void setNumerador(Integer a) { numerador = a; } public void setDenominador(Integer b){ if( b == 0) throw new IllegalArgumentException( "El Divisor no puede ser cero"); denominador = b; } public void suma(Racional r) { Integer a= getNumerador()*r.getDenominador() + getDenominador()*r.getNumerador(); Integer b = getDenominador()*r.getDenominador(); setNumerador(a); setDenominador( b); } public void resta(Racional r){ Integer a=getNumerador()*r.getDenominador()getDenominador()*r.getNumerador(); Integer b = getDenominador()*r.getDenominador(); setNumerador(a); setDenominador( b); } public void multiplica(Racional r){ Integer a = getNumerador()*r.getNumerador(); Integer b = getDenominador()*r.getDenominador(); setNumerador(a); setDenominador( b); } public void divide(Racional r){ if(r.getNumerador() == 0) throw new ArithmeticException( "No se puede dividir entre cero"); Integer a = getNumerador()*r.getDenominador(); 11 Práctica 4: Diseño de tipos Integer b = getDenominador()*r.getNumerador(); setNumerador(a); setDenominador(b); } public void invierte(){ if(getNumerador() == 0) throw new ArithmeticException( "No se puede invertir si el numerador es cero"); Integer a = getNumerador(); Integer b = getDenominador(); if( getNumerador() > 0){ setNumerador(a); setDenominador( b); } else { setNumerador(-a); setDenominador( -b); } } public Racional clone(){ Racional copia = null; try { copia = (Racional) super.clone(); }catch(CloneNotSupportedException e){ e.printStackTrace(); } return copia; } public String toString(){ String s = getNumerador().toString(); if(!getDenominador().equals(1)){ s = s + "/" + getDenominador(); } return s; } public boolean equals (Object r){ boolean res = false; if(r instanceof Racional){ Racional r1 = (Racional) r; Integer prod1 = getNumerador()*r1.getDenominador(); Integer prod2 = getDenominador()*r1.getNumerador(); res = prod1.equals(prod2); } return res; } public int hashCode(){ Integer n = getNumerador(); Integer d = getDenominador(); Integer mcd = Enteros.mcd(n,d); n = n/mcd; d = d/mcd; return n.hashCode()*31 + d.hashCode(); } public int compareTo(Racional r){ Integer prod1 = getNumerador()*r.getDenominador(); Integer prod2 = getDenominador()*r.getNumerador(); return prod1.compareTo(prod2); } } 12