Algo1 - TADs Imp.pptx

Anuncio
Qué&es&un&Tipo&de&Datos&
Tipos&Abstractos&de&datos&
Tipos&básicos&vs&compuestos&
•  Básicos:&
–  Provistos&por&el&lenguaje&
–  No&sabemos&como&se&representan&
–  Los&accedemos&mediante&operaciones&o&usando&
constantes&
•  Compuestos4
–  Se&arman&componiendo&Xpos&básicos&
•  Se&puede&acceder&o&no&a&la&representación&
–  Se&pueden&definir&operaciones&para&manipularlos&
Un&!po&define:&
•  Un&conjunto&de&valores&
•  Las&operaciones&que&puedo&realizar&sobre&estos&
valores&
&
Ejemplos:&
?  int:&
&valores&=&{&…,&?2,?1,&0,&1,&2,&…},&
&
&
&operaciones:&{+,*,?,&%,&…}&
?  char:& &valores&=&{&…,&‘a’,’b’,’c’,&…},& &
&
&
&operaciones:&{ord,&toUpperCase,…}&&
?  int[]:& &valores&=&{[Int]},&&
&
&operaciones:{length,&[.]}&&
Básicos4
int&
int&
1004
float&
54
char&
2.34
‘a’4
Compuestos4
Complejo&
real:4104
Imag:454
Racional&
numer:414
denom:424
Persona&
nom:4Juan4
ap:4Perez4
nacido:422/4/19744
Tipos&abstractos&de&datos&
•  Un&Tipo4Abstracto4de4Datos4(TAD)&define&su&
conjunto&de&valores&a&parXr&de&sus&operaciones&o&
propiedades,&independientemente&de&
implementaciones&parXculares.&&
Cómo&se&uXliza&el&Xpo?&&
•  A&travéz&de&sus&operaciones&y&únicamente&así&&
•  No&se&puede&acceder&a&su&representación&interna&
–  Usamos&sólo&su&especificación&en&el&Tipo&Compuesto&
TADs&en&Java&=&Clases&y&Objetos&
“Objeto(es(una(unidad(que(encapsula(un(estado(y(4ene(un(
un(determinado(comportamiento”(
&
Un&objeto&Xene&una&&
?  Iden!dad:&para&poder&disXnguirse&de&otros&objetos&
?  Comportamiento:&qué&puede&hacer.&Qué&operaciones&
sabe&hacer.&
?  Estado:&valores&de&sus&atributos&en&un&instante&de&
Xempo&dado&
•  No&solo&por&convicción:&no&tenemos&otro&remedio!&
El&estado&suele&estar&oculto,&solo&se&suele&interactuar&con&
un&objeto&enviándole&mensajes.&
TADs&en&Java&=&Clases&y&Objetos&
Ejemplos&
•  Mecanismo&para&crear&objetos&
–  En&Java,&elementos&del&Xpo&que&define&la&clase&
•  Es&un&“molde”&que&indica&&
–  Qué&posibles&valores&tendra&su&estado44
–  La&definición&de&los&métodos&(operaciones)&
implemetará&&
•  Esto&determina&qué&mensajes&sabra&responder&
&
En&Java,&implementamos&TADs&definiendo&clases.&
Estos&luego&instancian&objetos&que&solo&pueden&
ser&accedidos&mediante&operaciones.&
•  Tipo&Complejo&
–  Parte&Real&
–  Parte&Imaginaria&
•  Operaciones&
Tipo Complejo {
observador Real(c: Complejo): Float;
observador Imag(c: Complejo): Float;
problema crear(r,i: Float)= res: Complejo {
asegura Real(res) = r;
asegura Imag(res) = I;
}
problema sumar(c1,c2: Comple) = res: Complejo {
…
}
}
&crear&sumar,&restar,&…&&
Implementación&del&Xpo&Complejo&
Nombre&del&Xpo&&
class Complejo {
private float real, imag;
Representación&interna&(estado)&
public Complejo(float r,float i) {
this.real = r;
this.imag = i;
}
public Complejo() {
real = 0; imag = 0;
}
public void sumar(Complejo c) {
this.real = this.real + c.real;
this.imag = this.imag + c.imag;
}
public float getReal(){
return real;}
public float getImag() {
return imag;}
}
Constructor&(crea&instancias&del&
Xpo&con&valores&válidos)&
“this”&representa&el&objeto&que&
se&está&operando.&&
Cuando&se&accede&a&un&campo&o&
método,&“this”&se&asume&si&no&se&
indica&otra&cosa.&
Operaciones&del&Xpo&(algunas&
pueden&modificar&el&estado)&
Encapsulamiento&y&Ocultamiento&
•  Acceso&a&representación&interna&en&muy&pocos&
métodos&
–  Muy&cerca&una&de&otra&en&el&código&(misma&clase)&
–  Si&cambia&la&representación&interna,&solamente&hay&que&
cambiar&esas&funciones&
&
•  Si&no&pedimos&al&lenguaje&esta&protección&
–  Riesgo&de&usar&representación&interna&en&otros&programas&
•  Nosotros&mismos&u&otro&programador&
–  Cuando&la&cambiemos,&dejan&de&funcionar&&
–  Y&hay&que&modificar&uno&por&uno!!!&
Funciones&proyectoras&(para&
mostrar&parte&del&estado)&
Instanciando&objetos&
La&instrucción&new4instancia&objetos&de&una&clase,&llamando&a&
un&constructor&y&devolviendo&una&referencia&al&nuevo&objeto.&&
&
c1&
Complejo&
Ejemplos:&
real:404
Complejo c1 = new Complejo();
Complejo c2 = new Complejo(10,5);
Imag:404
c2&
Complejo&
Tipo&Racional&
•  Queremos&un&componente&que&nos&maneje&
números&racionales&de&forma&precisa&
•  Ejemplos&&
–  1&,&1/2&,&2/3&,&23/10,&2/4&
Racional&
numer:414
denom:414
real:4104
Imag:454
&
?&Los&parámetros&determinan&a&que&constructor&llamar&
c1.sumar(c2);
?&En&una&invocación,&el&primer&parámetro,&se&lo&llama&receptor&
(va&&a&ser&el&“this”&en&el&método)&
•  Operaciones&deseables&
–  Crear&
–  Sumar,&Restar,&MulXplicar&
–  …&
Racional&
numer:424
denom:434
Racional&
numer:414
denom:424
Representando&racionales&
•  Idea:&usar&&numerador&y&denominador&&
class Racional
•  Listo?&
{
private
private
public
public
public
public
public
public
public
int
int
int
int
numerador;
denominador;
getNumerador();
getDenominador();
Racional(int n, int d);
bool equals(Racional r);
void sumar(Racional r);
void restar(Racional r);
void multiplicar(Racional r);
Representando&racionales&
•  Conviene&tener&una&&forma&uniforme&de&
representar&
class Racional
{
private int numerador;
private int denominador;
// invRep mcd(numerador, denominador)==1
denominador!=0;
public
public
public
public
public
public
public
}
! 
! 
No!&Ningun&racional&es&representado&por&n/0;&
Diferentes&representaciones&para&el&mismo&racional!&
!  (1,2),(2,4),(3,6)…&&
Representando&racionales&
Invariante4 de4 Representación:& predicado& que& indica& una&
propiedad&fundamental&que&debe&mantenerse&en&el&objeto&
ahora&(2,4)&&
y&(x,0)&&no&son&&
racionales!&
&&
int getNumerador();
int getDenominador();
Racional(int n, int d);
bool equals(Racional r);
void sumar(Racional r);
void restar(Racional r);
void multiplicar(Racional r);
}
! 
Aun&se&“cuelan”&(1,?2),&(?1,2)&
Invariantes&de&Representación&(o&Clase)&
•  Propiedad&fundamental&que&debe&cumplir&un&
objeto&&
–  Para&el&que&el&objeto&esté&en&un&estado&consistente&
class Racional
{
private int numerador;
private int denominador;
// invRep mcd(numerador, denominador)==1
public
public
public
public
public
public
public
}
&& denominador>0;
•  Fuera&de&la&clase&debe&ser&siempre&verdadero&&
–  Pensar&en&un&Xpo&compuesto&
int getNumerador();
int getDenominador();
Racional(int n, int d);
bool equals(Racional r);
void sumar(Racional r);
void restar(Racional r);
void multiplicar(Racional r);
•  Internamente&
–  Puede&ser&asumido&por&los&métodos&de&la&clase&
–  Debe&ser&mantenido&también&por&ellos&
Invariantes&de&TC&vs.&invRep&
•  Un&invariante4de4un4Tipo4Compuesto4es&
siempre&verdadero&
Implementación&del&constructor&
•  Algún&problema&con&esto?&
–  En&los&asegura&de&los&problemas&tenemos&que&ver&
si&invariante+asegura&no&es&una&contradicción&
&
class Racional
{
private int numerador;
private int denominador;
// invRep mcd(numerador, denominador)==1 && denominador>0;
•  Un&invRep&es&verdadero&
public Racional(int n, int d){
–  Siempre&afuera4de4la4clase4
–  Dentro&de&la&clase: &&
numerador = n;
denominador = d;
}
•  Se&asume&verdadero&en&la&entrada&de&los&métodos&
•  Tenemos&que&garan!zar&que&sea&verdadero&a&la&salida&
}
Implementación&del&constructor&
•  Algún&problema&con&esto?&
class Racional
{
private int numerador;
private int denominador;
// invRep mcd(numerador, denominador)==1&& denominador>0;
public Racional(int n, int d){
// requiere d>0;
numerador = n;
denominador = d;
}
}
Implementación&del&constructor&
•  Ahora&sí&
class Racional
{
private int numerador;
private int denominador;
// invRep mcd(numerador, denominador)==1 && denominador>0;
public Racional(int n, int d){
// requiere d!=0;
int mcd = Math.gcd(n,d);
numerador = Math.sign(d)*n/mcd;
denominador = Math.abs(d)/mcd;
}
}
Implementando&operaciones&
Invariantes&y&abstracción&
Podemos&asumir&el&invariante,&pero&debemos&restablecerlo&
class Racional
{
private int numerador;
private int denominador;
// invRep mcd(numerador, denominador)==1
&& denominador>0;
// requiere r no es sinónimo de this
public void suma(Racional r){
This.inv&
numerador = numerador*r.denominador
+ r.numerador * denominador;
This.inv&
denominador = denominador*r.denominador; This.inv&
This.inv?&
}
int
mcd
=
Math.gcd(numerador,denominador);
This.inv&
}
numerador = numerador/mcd;
This.inv&
denominador = denominador/mcd;
This.inv&
}
}
&
class C {
private int x,y;
public dividir(){
// requiere y!=0;
x = 100/y;
}
}
r.inv& ?&
Helper&methods&
•  Los&invariantes&deben&valer&a&la&entrada&y&salida&del&método&
–  A&veces&esto&es&muy&restricXvo&
•  Helper&methods:&&
–  Tienen&que&ser&privados&
–  No&requieren&que&valga&el&invariante&
–  Ni&establecer&el&invariante&
class Racional
{
private int numerador;
private int denominador;
invRep mcd(numerador, denominador)== 1
&& denominador>0;
public void suma(Racional r){
numerador n = numerador*r.denominador
+ r.numerador * denominador;
denominador =denominador*r.denominador;
reconstuir();
}
}
•  Pregunta:&Qué&problema&le&ven&a&este&método?&
// helper:
private void reconstruir()
{
int mcd = Math.gcd(numerador,
denominador);
numerador = numerador/mcd;
denominador = denominador/mcd;
}
&
!  Mejor&este!&
class C {
private int x,y;
// invRep y!=0;
public dividir(){
x = 100/y;
}
}
Resumen&
•  Un&objeto&“compuesto”&necesita&estar&en&un&
estado&consistente&
•  Esta&garanqa&puede&lograrse&mediante&el&uso&
de&invariantes&
•  Mantener&el&invariante&requiere&un&esfuerzo&
del&programador&&
–  Pero&facilita&implementación&de&código&que&sea&
correcto&porque&se&debe&ser&consciente&de&&las&
presunciones&que&se&realizan&
Probrando&corrección&
•  Para&ver&si&una&clase&C&es&una&implementación&
correcta&de&un&Tipo&compuesto&T&tenemos&que&
ver&que:&
1.  El&invRep&se&manXene&en&todos&los&métodos&
públicos&
?&Notar&que&se&especifica&usando&los&campos4de4la4clase4
4
2.  Los&métodos&&públicos&cumplen&con&su&contrato&
&&&&&?&Notar&que&se&especifica&usando&los&observadores4del4
!po4
QPQ mcd(numerador, denominador)== 1 && denominador>0&
// implica numerador == numerador@e1*r.denominador
+ r.numerador *denominador@e1
&& denominador ==denominador@e1 *r.denominador
int mcd = Math.gcd(numerador,denominador);
// estado e4
// vale this==this@e3 && mcd==mcd(numerador@e3,denominador@e3)
numerador = numerador/mcd;
// estado e5
// vale numerador == numerador@e4/mcd@e4 && denominador ==
denominador@e4 && mcd==mcd@e4
denominador = denominador/mcd;
// estado e6
// vale denominador == denominador@e5/mcd && numerador == numerador@e5
&& mcd==mcd@e5
… (me&salteo&algunos&implicas)
// implica numerador == numerador@e3/mcd(numerador@e3,denominador@e3)
&& denominador == denominador@e3/mcd(numerador@e3,denominador@e3)
// implica denominador>0 (denominador@e3>0&y&mcd&es&posiXvo)&
// implica mcd(numerador,denominador)==1 (ambos&fueron&divididos&por&el&mcd)&
// implica invRep(this)4
}
&
Preservación&de&invRep&
(asumimos&que&el&método&no&modifica&r,&solo&this)&
public void suma(Racional r) {
Recordar:&“this”&es&opcional&dentro&de&un&
método&de&la&clase&si&lo&que&se&referencia&
es&el&objeto&receptor&del&mensaje&
//vale invRep(this):mcd(numerador, denominador)== 1 && denominador>0;
//vale invRep(r):mcd(r.numerador, r.denominador)==1 && r.denominador>0;
// estado e1
numerador = numerador*r.denominador
+ r.numerador * denominador;
// estado e2
// vale numerador == numerador@e1*r.denominador + r.numerador *
denominador@e1 && denominador == denominador@e1
denominador =denominador*r.denominador;
// estado e3
// vale denominador ==denominador@e2 *r.denominador
&& numerador==numerador@e2
// implica numerador == numerador@e1*r.denominador
+ r.numerador*denominador@e1
&& denominador ==denominador@e1 *r.denominador
&
Probando&corrección&
Tipo Racional{
observador numerR(r: Racional): Int;
observador denomR(r: Racional): Int;
invariante denomR(r) > 0;
invariante mcd(numerR(r), denomR(r)) == 1;
}
problema crearR(n, d: Int) = rac: Racional {
requiere d≠0;
asegura numerR(rac) * d == denomR(rac) * n;
}
class Racional {
private int numerador, denominador;
// invRep mcd(numerador, denominador)==1
&& denominador>0;
public Racional(int n, int d){
// requiere d>0;
int mcd = Math.gcd(n,d);
numerador = n/mcd;
denominador = Math.abs(d)/mcd;
}
}
¿Cómo&probamos&que&es&
correcto?&
¿Cómo&relacionamos&el&estado&
de&un&objeto&de&Xpo&Racional&
(numerador,&denominador)&con&los&
observadores&del&Xpo&
compuesto&Racional&(numerR,&
denomR)?&
Predicado&de&Abstracción&
•  abs(this:&clase,&e:&TipoCompuesto):&predicado&que&
relaciona&una&instancia&concreta&de&una&clase&con&un&
elemento&de&su&&Xpo&de&especificación.&
class Racional {
private int numerador, denominador;
// invRep: mcd(numerador, denominador)==1
&& denominador>0;
// abs(this,rac): numerR(rac)==numerador
&& denomR(rac)==denominador
public Racional(int n, int d){
// requiere d!=0;
int mcd = Math.gcd(n,d);
numerador = Math.sign(d)*n/mcd;
denominador = Math.abs(d)/mcd;
}
}
Demostrando&
problema crearR(n, d: Int) = rac: Racional {
requiere d≠0;
asegura numerR(rac) * d == denomR(rac) * n;
}
class Racional {
private int numerador, denominador;
// invRep: mcd(numerador, denominador)==1 && denominador>0;
// abs(this,rac): numerR(rac)==numerador && denomR(rac)==denominador
public Racional(int n, int d){
// requiere d!=0; (notar&que&es&&d≠0 equivalente,&Xene&que&ser&mas&fuerte)
int mcd = Math.gcd(n,d);
numerador = Math.sign(d)*n/mcd; denominador = Math.abs(d)/mcd;
…
//implica numerador==sign(d)*n/mcd(n,d) && denominador==|d|/mcd(n,d)
(ahora&usando&que&mcd!=0&y&&abs(this,rac)&)
//implica numerR(rac)==sign(d)*n/mcd(n,d) && denomR(rac)==|d|/mcd(n,d)
(divimos&numerR/denomR)
//implica numerR(rac)/denomR(rac)==(sign(d)*n/mcd(n,d))*(mcd(n,d)/|d|)
(simplificamos&y&usamos&que&d≠0)
// implica numerR(rac) * |d| == denomR(rac) * sign(d)*n;
// implica numerR(rac) * |d|/sign(d) == denomR(rac) *n;
// implica numerR(rac) * d == denomR(rac) * n;
Abs&vs.&InvRep&
InvRep:&determina&cuándo&el&estado&de&un&
objeto&es&consistente&
–  Es&una&propiedad&solo&de&la&representación&
–  Por&eso&debe&ser&mantenido&
Abs:&explica&cómo&la&implementación&es&una&
solución&del&Xpo&compuesto&
–  Conecta&representación&interna&con&observadores&
–  Asume&que&tanto&InvRep4como&invariante4del4TC&
son&verdaderos&
Ejercicio&
•  Especificar&el&problema&sumar&&y&demostrar&que&este&&método&es&
correcto.&
•  Hint:&Aprovechar&parte&de&la&prueba&de&conservación&de&invRep&
class Racional {
private int numerador, denominador;
// invRep: mcd(numerador, denominador)==1
&& denominador>0;
// abs(this,rac): numerR(rac)==numerador
&& denomR(rac)==denominador
public void suma(Racional r){
numerador = numerador*r.denominador
+ r.numerador * denominador;
denominador = denominador*r.denominador;
reconstruir();
}
}
Representación&!=&Especificación&
Ejemplo:&Lista&con&Lista&de&arrays&
Estamos& obligados& a& implementar& solo4 los&
problemas&definidos&en&el&Xpo&compuesto&
–  No&hay&necesidad&de&implementar&los&
observadores!&
–  Los&campos&elegidos&para&implementar&no&Xenen&
porque&ser&iguales&a&los&observadores&
–  Tampoco&hay&que&implementar&funciones&que&los&
calculen&
El& predicado& abs& se& ocupa& de& explicar& como&
relacionar&representación&con&especificación.&
0"
Cual&es&el&Abs?&
1"
2"
3"
4"
5"
6"
7"
8"
Tipo Lista<T>{
observador elems(l: Lista<T>): [T];
}
problema iesimo(l: Lista<T>, i: Int) = res: T {
requiere |elems(l)|>0 && 0<=i<|elems(l)|;
asegura res = elems(l)[i]
}
problema agregar(l: Lista<T>, e: T) {
modifica l;
asegura elems(l) = elems(l@pre) ++ [e];
}
04
14
24
34
44
54
64
74
104 114 124 134 144
count=15,&nextPos=5&
class Lista<T> {
private LinkedList<T[]> L;
private int count, nextPos;
// invRep count = 10*(|L|-1)+nextPos && todos([|b|==10| b<-L])
&& 0<=nextPos<10;
public Lista(){
nextPos=0; count= 0;
L = new LinkedList<T>();
L.add(new T[10]);
}
9"
Ejercicio&
10" 11" 12" 13" 14"
count=15,*nextPos=5*
abs(this, l) : |elems(l)|==count
&& todos([elems(l)[i]==this.L[i div 10][i % 10]
| i <- [0..this.count) ])
class Lista<T> {
private LinkedList<T[]> L;
private int count, nextPos;
// invRep count = 10*(|L|-1)+nextPos && todos([|b|==10| b<-L])
&& 0<=nextPos<10;
public T iesimo(int i){
// requiere count>0 && 0<=i<count
int pos = i div 10;
T res = L.get(pos)[i % 10];
}
}
•  Implementar&el&método&agregar&
Tipo Lista<T>{
observador elems(l: Lista<T>): [T];
}
problema iesimo(l: Lista<T>, i: Int) = res: T {
requiere |elems(l)|>0 && 0<=i<|elems(l)|;
asegura res = elems(l)[i]
}
problema agregar(l: Lista<T>, e: T) {
modifica l;
asegura elems(l) = elems(l@pre) ++ [e];
}
04
14
24
34
44
54
64
74
count==8,&nextPos==8,&|L|==1&
84
94
Ejercicio&
•  Implementar&el&método&agregar&
Ejercicio&
•  Implementar&el&método&agregar&
Tipo Lista<T>{
observador elems(l: Lista<T>): [T];
}
problema iesimo(l: Lista<T>, i: Int) = res: T {
requiere |elems(l)|>0 && 0<=i<|elems(l)|;
asegura res = elems(l)[i]
}
problema agregar(l: Lista<T>, e: T) {
modifica l;
asegura elems(l) = elems(l@pre) ++ [e];
}
l.agregar(8)&
04
14
24
34
Tipo Lista<T>{
observador elems(l: Lista<T>): [T];
}
problema iesimo(l: Lista<T>, i: Int) = res: T {
requiere |elems(l)|>0 && 0<=i<|elems(l)|;
asegura res = elems(l)[i]
}
problema agregar(l: Lista<T>, e: T) {
modifica l;
asegura elems(l) = elems(l@pre) ++ [e];
}
l.agregar(9)&
44
54
64
74
84
count==9,&nextPos==9,&|L|==1&
Conclusiones&
•  TADs:&Permiten&definir&Xpos&de&acuerdo&al&
comportamiendo,&ocultando&su&estructura&
interna&
•  En&Java&los&implementamos&usando&clases.&
•  Conceptos&claves:&
–  Invariante4de4Representación:&Para&que&los&
objetos&sean&consistentes&
–  Predicado4de4abstracción:&conectan&la&
especificación&del&TAD&con&su&implementación&
04
14
24
34
44
54
64
74
84
94
count==10,&nextPos=0,&|L|==2&
Especificación&de&Contratos&en&Componentes&
•  Un&componente&implementa&alguna&enXdad&o&
elemento&importante&en&nuestra&solución&
–  Componente&=&conjunto&de&clases&
–  Clase&=&conjunto&de&métodos&que&implementan&un&
TAD&
•  Contratos&
–  Por&cada&método:&&Requiere,&Asegura4
–  A&nivel&clase:&invRep&
–  A&nivel&componente:&sistemas&de&ownerships&+&
invariantes&conectados&entre&objetos&
Metodologías&de&uso&de&invariantes&
•  Problemas&potenciales&
–  Exponer&la&representación&
–  Reentrada&
•  SemánXcas&de&invariantes&que&tratan&de&lidiar&
con&esto&
–  Obligar&a&restablecer&el&invariante&en&cada&llamada&
–  Ownership&type&system&
•  Se&busca&que&el&invariante&siempre&valga&al&inicio&
de&un&método&
Preguntas&
Descargar