INGENIERÍA DEL SOFTWARE. 4º ING. INFORMÁTICA (UPV/EHU) 31 de MAYO de 2001 NOMBRE: GRUPO: 1.- Es posible que un sistema que no ofrezca mecanismos de HERENCIA presente la característica conocida por POLIMORFISMO? Razona la respuesta. (0,5 ptos.) No es posible. POLIMORFISMO es una característica OO que permite que variables del tipo (clase) X puedan contener instancias de subclases de X. No se pueden definir subclases si no hay HERENCIA NOTA: una respuesta contraria justificándola como que se puede tener POLIMORFISMO en un sistema que sólo ofrezca mecanismos de interfaces como el de Java será considerada válida. 2.- Qué es EXTENSIBILIDAD y REUTILIZACIÓN del software? Qué características propias de los sistemas OO favorecen la EXTENSIBILIDAD y la REUTILIZACIÓN y por qué? (1 pto.) EXTENSIBILIDAD es un factor de calidad del software que consiste en la facilidad de adaptación del software a nuevos requisitos o cambios en la especificación. REUTILIZACIÓN es otro factor de calidad que consiste en crear elementos de software que sirvan para construir distintas aplicaciones. El POLIMORFISMO, la LIGADURA DINÁMICA (así como el mecanismo de INTERFACES que se basa en ellos) favorecen la EXTENSIBILIDAD y REUTILIZACIÓN. Una clase que computa algo útil con objetos de una clase P (o interfaz I) PUEDE REUTILIZARSE para objetos de cualquier subclase de P (o clase que implemente I). Se PUEDE EXTENDER (y cambiar) el comportamiento de una clase definiendo una subclase que añada y/o redefina métodos existentes. La LIGADURA DINÁMICA asegurará que sean estos últimos los que se ejecuten. 3.- En el Proceso Unificado de Desarrollo de software, se considera que la CAPTURA DE REQUISITOS, ANÁLISIS, DISEÑO, IMPLEMENTACIÓN y PRUEBAS constituyen las FASES del proyecto? (0,5 ptos.) No. Son los FLUJOS DE TRABAJO (el conjunto de actividades) a realizar a lo largo del Ciclo de Vida del proyecto (que, por cierto, es el que se divide en FASES que terminan con ciertos HITOS, y que a su vez están formadas por ITERACIONES) 4.- Explica qué son los RESGUARDOS, en qué PARTE del ciclo de vida de un proyecto tienen importancia y cuál es su función. (0,5 ptos.) Un RESGUARDO es un programa/módulo que sustituye a otro y que se comporta como si se hubiera llamado al módulo real (aunque existen distintas posibilidades). Los RESGUARDOS se utilizan en el flujo de trabajo de PRUEBAS. Cuando se prueba un módulo que llama a otros módulos y no se sabe si estos últimos son correctos (en INTEGRACIÓN DESCENDENTE) se sustituyen por RESGUARDOS y así, si los resultados no son los esperados, entonces se sabe que el módulo erróneo es el que llama al RESGUARDO.
5.- Programar el siguiente método (que es uno de los algoritmos reutilizables de JGL) (1,25 pto.) * @param container Un contenedor. * @param predicate Un predicado unario. * @return Nuevo contenedor que tiene los elementos que satisfacen el predicado public static Container select( Container container, UnaryPredicate predicate ); perteneciente a la clase public final class Filtering public static Container select(container container, UnaryPredicate predicate) { Container nuevo = container.clone(); Object o; nuevo.clear(); Enumeration e = container.elements(); while (e.hasmoreelements()) { o=e.nextelement(); if (predicate.execute(o)) nuevo.add(o); return nuevo; 6.- Utilizando el algoritmo Filtering.select de JGL, se pide completar el siguiente código para que, dado un Array JGL que contiene varias personas (objetos de la clase Pers definida en el ANEXO), se obtenga otro Array JGL con solamente las personas pertenecientes al primer Array que sean rubias. (1,25 pto.)- Array contenedor = new Array( ); contenedor.add(new Pers("pepe",32,"RUBIO")); contenedor.add(new Pers("ana",33,"RUBIO")); contenedor.add(new Pers("pepe",30,"CASTAÑO"));... // COMPLETA ESTE CÓDIGO USANDO Filtering.select(...); Array res = Filtering.select(contenedor, new SeleccionarRubios()); Donde se define la clase: public class SeleccionarRubios implements UnaryPredicate { public boolean execute (Object o) { return (Pers)o.esRubio(); 7.- La interfaz de usuario asociada a un caso de uso llamado CONSULTAR PRECIO aparece a continuación, junto con la clase Java correspondiente: (2,5 ptos.)
import java.awt.*; import java.awt.event.*; public class ConsPrecioIU extends Frame { Label label1 = new Label(); Panel panel1 = new Panel(); Button button1 = new Button(); Button button2 = new Button(); Panel panel2 = new Panel(); GridLayout gridlayout1 = new GridLayout(3,2); Label label2 = new Label(); TextField textfield1 = new TextField(); Label label3 = new Label(); TextField textfield2 = new TextField(); Label label4 = new Label(); TextField textfield3 = new TextField(); public ConsPrecioIU() { super(); try { jbinit(); catch (Exception e) { e.printstacktrace(); private void jbinit() throws Exception { this.settitle("frame Title"); label1.settext("consultar PRECIO"); label1.setalignment(label.center); button1.setlabel("consultar Precio"); button1.addactionlistener(new java.awt.event.actionlistener() { public void actionperformed(actionevent e) { button1_actionperformed(e); ); button2.setlabel("cancelar"); button2.addactionlistener(new java.awt.event.actionlistener() { public void actionperformed(actionevent e) { button2_actionperformed(e); ); label2.settext("manzanas (Kg.)"); label3.settext("peras (Kg.)"); label4.settext("naranjas (Kg.)"); panel2.setlayout(gridlayout1); this.add(label1, BorderLayout.NORTH); this.add(panel1, BorderLayout.SOUTH); panel1.add(button1, null); panel1.add(button2, null); this.add(panel2, BorderLayout.CENTER); panel2.add(label2, null); panel2.add(textfield1, null); panel2.add(label3, null); panel2.add(textfield2, null); panel2.add(label4, null); panel2.add(textfield3, null); this.pack(); this.setvisible(true); void button1_actionperformed(actionevent e) { void button2_actionperformed(actionevent e) {
Se dispone también de una clase llamada Aviso que sirve para crear Dialog modales asociados al objeto Frame actual. La llamada new Aviso(this,"Pulsa Aceptar y me voy"); crearía lo siguiente: Además, nos han proporcionado los siguientes métodos, los cuales no sabemos ni a qué clase pertenecen ni qué es lo que hacen exactamente, pero nos han dicho que son útiles para acceder a los datos almacenados en la siguiente tabla de una BD Access. Además nos dicen que dicha BD es accesible por medio de una fuente de datos ODBC llamada PRODS public void inicializarbd () { try { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); conexion=drivermanager.getconnection("jdbc:odbc:prods"); sentencia=conexion.createstatement(); catch(exception e){system.out.println("error"+e.tostring()); public float getprecio(string nombre) { try{ rs=sentencia.executequery("select PRECIO FROM PRODUCTOS "+ "WHERE NOMBRE='"+nombre+"'"); if (rs.next()) return rs.getfloat("precio"); catch (Exception e) {System.out.println("Error: "+e.tostring()); return 0; Se pide: Rellenar la clase ConsPrecioIU con el código necesario para que al pulsar el botón CONSULTAR PRECIO aparezca como resultado el precio de los productos escogidos. Por ejemplo, el resultado sería el siguiente: si los precios actuales fueran los que aparecen en la tabla ACCESS anterior y se hubiera pulsado el botón CONSULTAR PRECIO con los siguientes datos de entrada:
NOTA1: Sólo se admitirá una solución que A) Utilice una arquitectura lógica en 3 niveles. Indicar cuáles son esos niveles y qué partes de código y/o clases pertenecen a cada nivel. B) Sea extensible ante el siguiente cambio en la lógica del negocio. Se van a aplicar porcentajes de descuento a cada producto dependiendo de la cantidad de Kg. que se compre. Indicar por qué la solución propuesta es extensible ante ese cambio. NOTA2: Indicar CLARAMENTE dónde se debe añadir el código en la clase ConsPrecioIU y dónde hay que declarar los métodos inicializarbd () y getprecio(string nombre) SOLUCIÓN: El cuerpo del procedimiento void button1_actionperformed(actionevent e) { de la clase ConsPrecioIU podría ser: Precios p = new Precios(); // Creación de un objeto lógica del negocio float precio = p.calcularprecio(textfield1.gettext(), textfield2.gettext(), textfield3.gettext()); Aviso a = new Aviso(this,"Precio es: "+precio); Existirá una clase con la lógica del negocio Precios que además podrá contener los métodos que llaman al nivel de datos: inicializarbd () y getprecio(string nombre) y el siguiente: public float calcularprecio(string kgmanz, String kgper, String kgnar) { float m,p,n; try{m=float.parsefloat(kgmanz); catch (Exception ex) {m=0; try{p=float.parsefloat(kgper); catch (Exception ex) {p=0; try{n=float.parsefloat(kgnar); catch (Exception ex) {n=0; return m*getprecio("manzanas (Kg.)")+p*getPrecio("PERAS (Kg.)") + n*getprecio("naranjas (Kg.)"); NIVEL DE PRESENTACIÓN: ConsPrecioIU y Aviso NIVEL DE LÓGICA DEL NEGOCIO: Precios (que incluye el código JDBC) NIVEL DE DATOS: La base de datos Access Justificación de por qué la solución es extensible: En el momento en el que haya que extender la aplicación para tratar el nuevo requisito, NO AFECTARÁ AL NIVEL DE PRESENTACIÓN. Sólo se
verán afectados el NIVEL DE DATOS (habrá que añadir tablas que permitan almacenar los descuentos para cada producto) y el NIVEL LÓGICA DEL NEGOCIO (que tendrá que calcular los nuevos precios aplicando los descuentos). NOTA: no sería necesario ni recompilar el nivel de presentación (la clase ConsPrecioIU). De hecho, se podría cambiar la lógica del negocio (proporcionar una nueva clase Precios) en tiempo de ejecución y no haría falta ni volver a crear el objeto gráfico (instancia de ConsPrecioIU)!! Esto último es cierto porque la instancia del objeto con la lógica del negocio se crea en el método de respuesta al evento del botón. La solución proporcionada es válida pero puede ser mejorada en algunos aspectos: (esto no se pedía) 1.- Los métodos inicializarbd () y getprecio(string nombre) se pueden poner en otra clase aparte (por ejemplo AccesoBD), la cual puede ser Singleton y que controle que sólo haya una conexión abierta (llamando a inicializarbd () en el constructor de la clase) 2.- Se puede no crear el objeto de negocio (instancia de Precios) dentro del método de respuesta al evento sobre el botón sino en el constructor de ConsPrecioIU para que sólo se haga una vez. También se podría pasar como parámetro en el método constructor un objeto con la lógica del negocio a aplicar. 3.- Se pueden ahorrar llamadas a getprecio(string nombre) en el método calcularprecio(...) de Precios, si se calculan y almacenan los valores de getprecio("manzanas (Kg.)"), getprecio("peras ),...(por ejemplo en el constructor de Precios).Esto sería válido sólo si los precios no cambiaran a lo largo de la vida del objeto de negocio (objeto de Precios). 8.- Existe otro caso de uso que sirve para consultar la disponibilidad de los productos (1,5 ptos) Describe cómo se puede definir una clase REUTILIZABLE que sirva para generar la Interfaz de Usuario del caso de uso CONSULTAR PRECIOS, del caso de uso CONSULTAR DISPONIBILIDAD y de cualquier otro caso de uso que pueda definirse en el futuro y que necesite una interfaz de usuario similar. NOTA: aseguraros de que permita ejecutar distintas acciones al pulsar el botón, dependiendo de qué caso de uso se trate. SOLUCIÓN: Se puede aplicar el patrón de diseño INTERFAZ Clase Consultar Consultar(IntConsultar i) usa interfaz IntConsultar gettitulo(): String gettituloboton(): String ejecutarboton(string s1,s2,s3): void
La clase reutilizable Consultar sería como la clase anterior ConsPrecioIU con los siguientes cambios: (en negrita) import... public class Consultar extends Frame { Label label1 = new Label();... TextField textfield3 = new TextField(); IntConsultar interfaz; public Consultar (IntConsultar i) { super(); try { interfaz=i; jbinit(); catch (Exception e) { e.printstacktrace(); private void jbinit() throws Exception { this.settitle("frame Title"); label1.settext(interfaz.gettitulo()); label1.setalignment(label.center); button1.setlabel interfaz.gettituloboton()); button1.addactionlistener(new java.awt.event.actionlistener() { public void actionperformed(actionevent e) { button1_actionperformed(e); );... label2.settext("manzanas (Kg.)"); label3.settext("peras (Kg.)"); label4.settext("naranjas (Kg.)");... void button1_actionperformed(actionevent e) { interfaz.ejecutarboton(textfield1.gettext(), textfield2.gettext(), textfield3.gettext()); Donde la definición de la interfaz es la siguiente: public interface IntConsultar { public String gettitulo(); public String gettituloboton(); public void ejecutarboton(string s1,string s2,string s3); Con la clase reutilizable Consultar se puede ver cómo se podrían crear objetos de la clase ConsPrecioIU del ejercicio anterior (la cual ya no sería necesaria): Consultar c = new Consultar(new ConsultarPrecios()); Donde ConsultarPrecios sería: public class ConsultarPrecios implements IntConsultar { public String gettitulo() { return CONSULTAR PRECIO ;
public String gettituloboton() {return Consultar Precio ; public void ejecutarboton(string s1, String s2, String s3) { Precios p = new Precios(); float precio = p.calcularprecio(s1,s2,s3); Aviso a = new Aviso(this,"Precio es: "+precio); 9.- Describe también cómo se puede conseguir que la clase que genera el interfaz gráfico sea REUTILIZABLE para cualquier producto, esto es, permita CONSULTAR PRECIOS, DISPONIBILIDADES, etc. de un conjunto de N productos cualesquiera y no sirva sólo para MANZANAS, PERAS y NARANJAS (1 pto) NOTA: no es necesario programarlo, sino indicar qué clases, métodos, etc. se necesitarían. SOLUCIÓN: Se puede aplicar el patrón de diseño INTERFAZ Clase Consultar Consultar(IntConsultar i) usa interfaz IntConsultar gettitulo(): String gettituloboton(): String ejecutarboton(enumeration e): void getproductos(): Enumeration Se deja como ejercicio el programarlo (no era necesario hacerlo en el examen)
ANEXO public interface Container extends Cloneable, Serializable { * Return a shallow copy of myself. public Object clone(); * Return a string that describes me. public String tostring(); * Return true if I'm equal to a specified object. * @param object The object to compare myself against. * @return true if I'm equal to the specified object. public boolean equals( Object object ); * Return the number of objects that I contain. public int size(); * Return the maximum number of objects that I can contain. public int maxsize(); * Return true if I contain no objects. public boolean isempty(); * Remove all of my objects. public void clear(); * Return an Enumeration of the components in this container public Enumeration elements(); * Return an iterator positioned at my first item. public ForwardIterator start(); * Return an iterator positioned immediately after my last item. public ForwardIterator finish();
* Add an object to myself. If appropriate, return the object that * displaced it, otherwise return null. public Object add( Object object ); * Remove the element at a particular position. public Object remove( Enumeration pos ); * Remove the elements in the specified range. public int remove( Enumeration first, Enumeration last ); public interface BinaryPredicate extends Serializable { * Return the result of executing with two Object arguments. * @param first The first object operand. * @param second The second object operand. * @return The boolean result of processing the input parameters. boolean execute( Object first, Object second ); public class Pers { private String nombre; private int dni; private String colorpelo; Pers(String n, int d, String c) { nombre=n; dni=d; colorpelo=c; public int getdni() {return dni; public String getnombre() {return nombre; public String getcolorpelo() {return colorpelo; public String esrubio() {return colorpelo.equals( RUBIO ); public String tostring() { return nombre + "/" + dni;