Download 1. Desarrollo de Programas iterativos usando invariante

Document related concepts
no text concepts found
Transcript
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
• Estrategia bottom-up: “partir” un problema en subproblemas, 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 subproblemas. 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;
int sum = (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 int horas(int x){ return x/10000;}
static public int minutos(int x){return x/100%100;}
static public int segundos(int x){return x%100;}
static public int totalSegundos(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;
}
public int compareTo(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);
}
public String toString() {
//retorna un string “HH:MM:SS”
return segundos/3600+”:”+(segundos%3600/60)+”:”+segundos%60;
}
}
Programa
class T {
public static void main(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.*;
public class Figura{
int ox, oy;
import java.awt.*;
public class Circulo extends Figura{
int radio;
Figura(int x, int y) {
ox= x; oy = y;
}
Circulo(int x, int y, int z) {
super(x, y); radio = z;
}
public double area(){
return 0.0;
}
public double area(){
return Math.PI*radio*radio;
}
public double perimetro(){
return 0.0;
}
public double perimetro(){
return 2*Math.PI*radio;
}
public void draw(Graphics g) {
g.fillCircle(ox-1,oy-1,ox+1,oy+1);
}
public void draw(Graphics g) {
g.fillCircle(ox-r/2,oy-r/2,
ox+r/2,oy+r/2);
}
}
}
Herencia Simple (cont.)
import java.awt.*;
public class Rectangulo extends Figura{
int largo, ancho;
Rectangulo(int x, int y, int l, in a) {
super(x,y); largo = l; ancho = a;
}
public double area(){
return largo*ancho;
}
public double perimetro(){
return 2*(largo+ancho);
}
import java.awt.*;
import java.util.*;
public class Prog {
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);
}
public void draw(Graphics g) {
g.fillRect(ox,oy,ox+ancho,oy+largo);
}
}
}
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.*;
public abstract class Figura{
int ox, oy;
Figura(int x, int y) {
ox= x; oy = y;
}
abstract public double area();
abstract public double area();
abstract public void draw(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{
int xo, yo;
public double area();
public double area();
public void draw(Graphics g);
}
import java.awt.*;
public class Circulo implements Figura{
int radio;
Circulo(int x, int y, int z) {
xo=x; yo=y; radio = z;
}
public double area(){
return Math.PI*radio*radio;
}
public double area(){
return Math.PI*radio;
}
public void draw(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 int compareTo(Object x);
}
class Fraccion implements Comparable{
int num, den;
Fraccion(int x, int y) { num = x; den = y;}
public int compareTo(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
Estructuras de Datos
¿Estructuras de datos?
Formas de organización y almacenamiento de datos (en
memoria). Ejemplos:
arreglo
lista enlazada
...
árbol
Estructura de Dato y su invariante
class Conjunto {
private int[] a;
private int 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;
}
public boolean sacar(int x) {
}
public boolean esta(int x) {
//retorna true si esta x en el conjunto
}
. . .
}
}