180 likes | 362 Views
4. Desarrollo de Programas: enfoques Top- down y Bottom -up. Idea. Objetivos: Facilitar el proceso de solución de un problema Orden y Claridad del código Distribución de tareas entre programadores
E N D
Idea • Objetivos: • Facilitar el proceso de solución de un problema • Orden y Claridad del código • Distribución de tareas entre programadores • Estrategia bottom-up: “partir” un problema en sub-problemas, solucionar los sub-problemas desarrollando código “encapsulado” y luego escribir el programa principal usando el código encapsulado • Estrategia top-down: Escribir el código del programa principal en forma gruesa, dejando para después la solución de sub-problemas. Luego se desarrollan los sub-problemas. • Distribución del trabajo: para distribuir el trabajo es necesario establecer claramente como se usarán y cual será el comportamiento del código encapsulado
Ejemplo Problema: desarrollar el programa que implementa el siguiente diálogo con el usuario: Suma, resta de 2 tiempos Primer tiempo (HHMMSS) ? 013040 Segundo tiempo (HHMMSS) ? 104530 Suma = 12:16:10 Resta = 09:14:50 Mayor = 10:45:30 Menor = 01:30:40
Solución sin estrategia: import java.util.*;class T { public static void main(String[] args) { Scanner C = new Scanner(System.in); System.out.println(“Sumar y resta de 2 tiempos”); System.out.print(“Primer instante(HHMMSS)?”); int t1=C.nextInt(); ht1=t1/10000; mt1=t1%10000/100; st1=t1%100; System.out.print(“Segundo instante(HHMMSS)?”); int t2=C.nextInt(); ht2=t2/10000; mt2=t2%10000/100; st2=t2%100; intsum = (ht1+ht2)*3600+(mt1+mt2)*60+st1+st2; System.out.print(“Suma= “+(sum/3600)+”:”+(sum%3600/60)+”:”+(sum%60)); int res = (ht1-ht2)*3600+(mt1-mt2)*60+st1-st2; System.out.print(“Resta= “+(res/3600)+”:”+(res%3600/60)+”:”+(res%60)); if (t1 > t2) System.out.print(“Mayor=“+ht1+”:”+mt1+”:”+st1); else System.out.print(“Mayor=“+ht2+”:”+mt2+”:”+st2); } }
Solución top down: import java.util.*;class T { public static void main(String[] args) { Scanner C = new Scanner(System.in); System.out.println(“Sumar y resta de 2 tiempos”); System.out.print(“Primer instante(HHMMSS)?”); int t1=Tiempo.totalSegundos(C.nextInt()); System.out.print(“Segundo instante(HHMMSS)?”); int t2=Tiempo.totalSegundos(C.nextInt()); System.out.print(“Suma=); Tiempo.escribir(t1+t2); int mayor=Math.max(t1,t2), menor=Math.min(t1,t2); System.out.print(“Mayor=); Tiempo.escribir(mayor); System.out.print(“Menor=); Tiempo.escribir(menor); System.out.print(“Resta=); Tiempo.escribir(mayor-menor); } } class Tiempo{ static public inthoras(int x){return x/10000;} static public intminutos(int x){return x/100%100;} static public intsegundos(int x){return x%100;} static public inttotalSegundos(int x){ return horas(x)*3600+minutos(x)*60+segundos(x);} static public void escribir(int x){ System.out.println(x/3600+”:”+x%3600/60+”:”+x%60);} }
Solución bottom-up: class Tiempo { int segundos; //conviene guardar el total de segundos no mas Tiempo (int x) { segundos = x/10000*3600+x/100%100*60+x%100; } publicintcompareTo(Tiempo x) { // retorna un entero < 0, == 0, > 0 según si x es mayor igual o menor return segundos – x.segundos; } public Tiempo suma(Tiempo x) { //retorna un objeto tiempo nuevo con la suma return new Tiempo(segundos+x.segundos); } public Tiempo resta(Tiempo x) { //retorna un objeto tiempo nuevo con la resta return new Tiempo(segundos-x.segundos); } publicStringtoString() { //retorna un string “HH:MM:SS” return segundos/3600+”:”+(segundos%3600/60)+”:”+segundos%60; } }
Programa class T { publicstaticvoidmain(String[] args) { Tiempo t1 = new Tiempo(C.readInt(“Primer instante(HHMMSS)?“)); Tiempo t2 = new Tiempo(C.readInt(“Segundo instante(HHMMSS)?”); Tiempo t3 = t1.suma(t2); System.out.print(“Suma=”+t3.toString()); if (t1.compareTo(t2) > 0){ mayor = t1; menor = t2; } else { mayor = t2; menor = t1; } U.println(“Mayor=“+mayor.toString()); U.println(“Menor=”+menor.tostring()); U.print(“Suma =“+(t1.suma(t2)).toString()+ ”Resta=”+(t1.resta(t2)).toString()); } }
Pensamientos • Es importante definir claramente la interfaz entre el programa principal y los sub-programas • El enfoque de llamado a funciones es más antiguo que el de diseñar y construir objetos pero ambos persiguen los mismos objetivos • El enfoque orientado a objetos responde a la necesidad de desarrollar software de grandes dimensiones con menos errores • Permite encapsular mejor el código y los datos de un subprograma • Apoya desarrollo de “Tipos de Datos Abstractos”
Herencia y Polimorfismo • Conceptos íntimamente ligados entre sí y a OOP • Herencia se refiere al uso de código ya escrito (una clase) que se extiende para “especializar” su función • Polimorfismo se refiere a que un objeto puede “verse” de varias clases diferentes a la vez • Estos conceptos se implementan con Herencia Simple, Clases Abstractas e Interfaces
Herencia Simple • La herencia simple consiste en extender una clase existente para: a) agregarle nuevas variables, b) agregarle nuevos métodos, c) modificar métodos import java.awt.*; publicclass Figura{ intox, oy; Figura(int x, int y) { ox= x; oy = y; } publicdoublearea(){ return 0.0; } publicdoubleperimetro(){ return 0.0; } publicvoiddraw(Graphics g) { g.fillCircle(ox-1,oy-1,ox+1,oy+1); } } import java.awt.*; publicclass Circulo extends Figura{ int radio; Circulo(int x, int y, int z) { super(x, y); radio = z; } publicdoublearea(){ returnMath.PI*radio*radio; } publicdoubleperimetro(){ return 2*Math.PI*radio; } publicvoiddraw(Graphics g) { g.fillCircle(ox-r/2,oy-r/2, ox+r/2,oy+r/2); } }
Herencia Simple (cont.) import java.awt.*; publicclassRectanguloextends Figura{ int largo, ancho; Rectangulo(int x, int y, int l, in a) { super(x,y); largo = l; ancho = a; } publicdoublearea(){ return largo*ancho; } publicdoubleperimetro(){ return 2*(largo+ancho); } publicvoiddraw(Graphics g) { g.fillRect(ox,oy,ox+ancho,oy+largo); } } import java.awt.*; importjava.util.*; publicclassProg { Arraylist<Figura> a = new ArrayList<Figura>(); a.add(new Rectangulo(50,50, 20,30)); a.add(new Circulo(100,100,30)); a.add(new Figura(50,50)); ... Frame f = new Frame(“Ventana de Figuras”); Canvas c = new Canvas(500,500); f.add(c); f.setVisible(true); ... Graphics g = c.getGraphics(); for (int i = 0; i <= a.size(); i++) { Figura n = a.get(i); n.draw(g); } }
Herencia con Clases Abstractas • Declaran clases incompletas con métodos abstractos • Los que extiendan esta clase DEBEN implementarlos • No es posible crear objetos de estas clases (si de sus extendidas) • No cambia ni el uso ni la definición de la clase extendida, salvo que el compilador obliga a implementar las funciones abstractas import java.awt.*; publicabstractclass Figura{ intox, oy; Figura(int x, int y) { ox= x; oy = y; } abstractpublicdoublearea(); abstractpublicdoublearea(); abstractpublicvoiddraw(Graphics g); }
Polimorfismo con Interfaces • Puede declarar variables comunes • Contiene encabezados (declaraciones) de funciones (métodos) que se deben implementar • Las clases “implementan” la interfaz, y con eso son también de la clase • El compilador tambien va a obligar a que la clase implemente todos los metodos de la interfaz/interfaces que declara implementar public interface Figura{ intxo, yo; publicdoublearea(); publicdoublearea(); publicvoiddraw(Graphics g); } import java.awt.*; publicclass Circulo implements Figura{ int radio; Circulo(int x, int y, int z) { xo=x; yo=y; radio = z; } publicdoublearea(){ returnMath.PI*radio*radio; } publicdoublearea(){ returnMath.PI*radio; } publicvoiddraw(Graphics g) { g.fillCircle(ox-r/2,oy-r/2, ox+r/2,oy+r/2); } }
¿Herencias, abstractos o Interfaces? • Depende (por algo existen las dos) • Herencia simple cuando se podrían usar los objetos de la clase original (superclase) • Clases abstractas cuando hay un conjunto de variables y funciones comunes, pero la clase “no esta lista” y por lo tanto no queremos que se usen objetos de la superclase • Interfaces cuando no hay nada que compartir, solo queremos asegurarnos que un objeto perteneciente a la clase de la interfaz tenga los métodos mencionados
Interfaz Comparable en Java • interface Comparable{ • public intcompareTo(Object x); • } • class Fraccion implements Comparable{ • intnum, den; • Fraccion(int x, int y) { num = x; den = y;} • public intcompareTo(Object x){ • Fraccion f=(Fraccion)x; • return a*f.b – b*f.a; • } • }
Estructura de Dato y su invariante • Cada estructura de datos que implementa un TDA tiene un invariante • Conjunto de condiciones que se cumplen siempre • Cada operación que se define sobre la estructura tiene el derecho de suponer que se cumple el invariante al principio y dejarlo cumpliéndose al final • Ej. Implementar un TDA conjunto con la siguiente estructura de datos a0 a1 . . . an-1 . . . n
Estructura de Dato y su invariante class Conjunto { privateint[] a; privateint n; Conjunto(int x) { a = new int[x]; n = 0; } public boolean agregar(int x) { if (esta(x)) return false a[n++] = x; return true; } publicboolean sacar(int x) { } publicboolean esta(int x) { //retorna true si esta x en el conjunto } . . . } }