POO en lenguajes compilados de tipos estáticos (Java y C#)

Anuncio
POO en lenguajes
compilados de tipos
estáticos (Java y C#)
Carlos Fontela
cfontela@fi.uba.ar
A3F
Temario
Modelo de referencias, creación y destrucción de objetos
(introducción)
Paquetes y grupos de clases
Constructores
Excepciones: captura y lanzamiento
Visibilidad
Herencia y transformaciones de tipos
Polimorfismo básico (basado en herencia)
2c2009
2
A3F
Creación de objetos
Declaración:
ArrayList x;
Definición:
x = new ArrayList( );
Significado
ArrayList es la clase de x
ArrayList( ) es el “constructor” de la clase ArrayList
El objeto se crea recién cuando llamo al constructor con
el operador “new”
En x queda una referencia a un objeto de tipo ArrayList
2c2009
3
A3F
Referencias
Las variables son referencias a objetos:
Date x, y;
x = new Date (2009, 7, 25);
y = x;
“x” e “y” referencian al mismo objeto
(hay una sola llamada a constructor)
Si hago:
y = new Date (1950, 8, 17);
Ahora “y” referencia a otro objeto
Una variable que no referencia un objeto tiene el valor
“null”
Puedo hacer: Date x = null;
2c2009
4
A3F
Recolección de basura
Si hago:
Date x;
x = new Date (2009, 7, 25);
x = new Date (1950, 8, 17);
El objeto inicial quedó como
basura
Java y C#
2c2009
5
A3F
Paquetes
Agrupación de clases, anidables
Para manejar complejidad y resolver nombres
Ejemplos:
ArrayList es java.util.ArrayList (Java)
ArrayList es System.Collections.ArrayList (C#)
import java.util.*;
// Java
import java.util.ArrayList;
// Java
using System.Collections;
// C#
En Java no es necesario importar las clases de
java.lang
2c2009
6
A3F
Paquetes y fuentes
Toda clase está en un paquete
En Java existe el paquete “default”, pero no es
recomendable usarlo
En C#, se enmarca el código de la clase en una
cláusula “namespace”:
namespace carlosFontela.cuentas { … }
En Java, cada clase pública va en un archivo
fuente separado
El paquete se indica en una cláusula “package”
package carlosFontela.cuentas;
2c2009
7
A3F
Implementaciones de
mensajes en C#
C# distingue “métodos” de “propiedades”
Métodos: para comportamiento de los objetos
lista.Add(-4);
saludo2 = s.Replace (‘a’, ’u’);
Propiedades: para consultar el estado
Console.WriteLine (lista.Count);
int longitud = saludo.Length;
En C# hay propiedades de clase:
DateTime ahora = DateTime.Now;
“Now” es una propiedad de clase de la clase “DateTime”
2c2009
8
A3F
Implementación de una
clase (1)
public class CuentaBancaria {
// atributos:
private int numero;
private String titular;
private double saldo;
// propiedad (sólo lectura):
public double getSaldo ( ) {
return saldo;
}
2c2009
9
A3F
Implementación de una
clase (2)
// métodos:
public void depositar (double monto) {
if (monto < 0)
throw new IllegalArgumentException ( );
saldo += monto;
}
public void extraer (double monto) {
if (monto > saldo)
throw new IllegalArgumentException ( );
saldo -= monto;
}
2c2009
10
A3F
Referencia this
Objeto o referencia “this”
public void depositar (double monto) {
if (monto < 0)
throw new IllegalArgumentException ( );
this.saldo = this.saldo + monto;
}
Invocación con el “objeto actual”
c.depositar (2000);
“this” referencia al “objeto actual”
2c2009
11
A3F
Implementación de una
clase (3)
// constructor:
public CuentaBancaria (int numero, String titular) {
if (numero <= 0 || titular == null || titular == “”)
throw new IllegalArgumentException ( );
this.numero = numero;
this.titular = titular;
this.saldo = 0;
}
} // fin de la clase
2c2009
12
A3F
¿Y en C#?
Hay propiedades como elemento del lenguaje
Uso:
Console.WriteLine ( c.Saldo );
Definición:
public double Saldo {
get {
return saldo;
}
}
2c2009
13
A3F
Excepciones: captura
Recordemos que las excepciones son objetos
Se acceden mediante variables que los referencian
Tienen estado, comportamiento e identidad
Por ejemplo:
try {
ArrayList lista = new ArrayList (-5);
}
catch (IllegalArgumentException e) {
e.printStackTrace();
}
2c2009
14
A3F
Excepciones: lanzamiento
Se crean y se lanzan hacia el módulo invocante
Sintaxis:
throw new ClaseException ( );
2c2009
15
A3F
Constructores
Se usan para inicializar
Si no se implementan hay uno por omisión
Para que toda clase tenga el suyo
Pero se pueden programar otros, como hicimos
En este caso, deja de existir el default
Debería dejar al objeto en un estado válido
=> debe cumplir con los invariantes
El default no es seguro
2c2009
16
A3F
Visibilidad (1)
Atributos, propiedades y métodos privados
Sólo se pueden usar desde dentro de la clase en que
están definidos
Atributos, propiedades y métodos públicos
Se los puede usar desde cualquier lado
Visibilidad de paquete (default, en Java)
Se los puede usar desde su mismo paquete
2c2009
17
A3F
Visibilidad (2)
Atributos y métodos protegidos (protected)
Son visibles sólo para las clases descendientes y las del propio
paquete
Poco uso; riesgos
Clases con visibilidad “de paquete”
Sólo se pueden usar dentro de su paquete
¿Clases privadas?
Sólo cuando son clases internas
No hay clases protegidas
2c2009
18
A3F
Atributos de clase
Supongamos que necesitamos que el número de
cuenta fuera incremental
Solución:
Agregar un atributo “numeroAcumulado” que mantenga
un único valor para la clase
Eso es un atributo de clase
En Java y C# “de clase” se dice “static”
OJO: Los miembros de clase no se heredan
2c2009
19
A3F
Java y .NET: clases
utilitarias
En Java y .Net toda función debe ir en una clase
Aunque trabajemos sin objetos
Usual agrupar funciones
Clase utilitaria
Agrupa métodos estáticos y/o constantes en una clase
Esta clase no se puede instanciar
Ejemplos
Arrays.sort(v);
double x = Math.pow(2,3);
double p = Math.PI;
2c2009
20
A3F
Java y .NET: sobrecarga
public CuentaBancaria (int numero, String titular) {
this ( numero, titular, 0);
}
public CuentaBancaria (int numero, String titular, int saldoInicial) {
if (numero <= 0 || titular == null || titular == “”)
throw new IllegalArgumentException ( );
this.numero = numero;
this.titular = titular;
this.saldo = saldoInicial;
}
2c2009
21
A3F
Java: no todo es un objeto
Las instancias de tipos primitivos no son objetos
int, long, double, char, boolean
Y se manejan por valor (no por referencia)
Hay “encajonamiento” o “autoboxing”
Integer x = 4; // significa Integer x = new Integer(4);
Arreglos “primitivos” no son objetos
int [ ] v = new int [4];
Pero se manejan por referencia
Tamaño se establece en tiempo de ejecución
Una vez establecido, no puede variar
Hay chequeo de rangos
Tipo de los elementos definido estáticamente
2c2009
22
A3F
C#: casi todo es un objeto
Los tipos primitivos son tipos por valor
Pero hay encajonamiento
Los arreglos son instancias de System.Array
Hay muchos tipos por valor
Pero se manejan como clases
Y se pueden definir por el programador
Con algunas restricciones
2c2009
23
A3F
Delegación
Un objeto contiene referencias a otros objetos y les delega
comportamiento
public class Segmento {
private Punto p1;
private Punto p2;
public double longitud ( ) {
return p1.distancia(p2);
}
...
}
2c2009
24
A3F
Herencia y lenguajes
En Java, para indicar herencia
public class Elipse extends Figura { ... }
En C# reemplazamos “extends” por “:”
public class Elipse : Figura { ... }
2c2009
25
A3F
Herencia, variables y
objetos
“Casteo” hacia arriba automático
Elipse e = new Elipse();
Figura f = e;
// e = f;
// válido y seguro
inválido e inseguro
Otro caso
public void p (Figura x) { … }
// … luego será invocado:
p(e);// e es de tipo Elipse
Los llamamos “objetos polimorfos”
Parecen una cosa pero son otra
f es una Elipse aunque se la trate como Figura
Figura f = new Elipse ( );
2c2009
// tipos distintos en la variable y el objeto !!
26
A3F
Herencia y arreglos
O arreglos polimorfos
public Figura[ ] v = new Figura [3];
// luego…
v[0] = new Elipse ( );
v[1] = new Circulo ( );
v[2] = new TrianguloRectangulo ( );
Pero
Estamos perdiendo información del objeto
Cada v[i] sólo va a tener disponibles los atributos y métodos públicos de
Figura
Ya volveremos sobre esto
2c2009
27
A3F
Particularidades de Java y
C#
Jerarquía de raíz única
Clase Object
Todo se puede transformar en un Object
Atributos y métodos comunes a todas las clases
Otras importantes consecuencias
Posibilidad de evitar la herencia
Declaramos la clase como “final”
Ejemplo: String
public final class String {...}
“sealed” en C#
2c2009
28
A3F
Constructores y herencia
Los constructores no se heredan
Cada clase debe tener el suyo
Receta
Llamar al constructor del ancestro al principio del constructor
propio
// Java:
public Derivada( ) {
super(); ... }
// C#:
public Derivada( ) : base ( ) {
... }
Automático con constructores por defecto
2c2009
29
A3F
Redefinición en Java y C#
Los métodos privados no pueden ser redefinidos
Se estaría definiendo uno nuevo
Posibilidad de evitar la redefinición
Métodos “final”
public final void m() {...}
“sealed” en C#
No se puede redefinir un método haciéndolo más privado
Sobrecarga y redefinición
Redefinición se hace con la misma firma
Si no, es sobrecarga
2c2009
30
A3F
Clases abstractas
No tienen instancias
Caso de CuentaBancaria si implemento CajaAhorro
Pero pueden tener constructor
¡que no debe ser llamado nunca!
Generalizan estructura y comportamiento de varias clases
Caso del método depositar
O crean una familia
Se declara “abstract”
2c2009
31
A3F
Analizar
CuentaBancaria cb = new CuentaBancaria(…);
CuentaCorriente cc1 = new CuentaCorriente(…);
CuentaBancaria cc2 = new CuentaCorriente(…);
cb.extraer(200);
cc1.extraer(200);
cc2.extraer(200);
2c2009
32
A3F
Métodos virtuales (1)
2c2009
33
A3F
Métodos virtuales (2)
// llama al dibujar de Elipse:
unaElipse.mover();
// llama al dibujar de Triangulo:
unTriangulo.mover();
// llama al dibujar de la clase de cada figura:
v.dibujarTodas();
// porque dibujar es virtual
En Java y en Smalltalk la “virtualidad” se da por defecto
En C# y C++ debemos declarar métodos como “virtual”
Métodos de clase, privados y finales no son virtuales
2c2009
34
A3F
Métodos virtuales (3)
Los métodos virtuales agregan ineficiencias
Pero garantizan reutilización
Eliminar la “virtualidad” sólo si se demuestra que no se
van a redefinir y la presunta ineficiencia
Un método debe ser virtual sí o sí cuando se lo
redefinirá y es llamado desde:
Un método en una clase ancestro
Un método que delegue en el método en cuestión de la
clase ancestro
2c2009
35
A3F
Ejemplo estándar en C#
En Object
public virtual String ToString ( ) { … }
Console.WriteLine usa ToString()
Si quiero que un objeto sea imprimible, debo redefinir ToString:
En CuentaBancaria
public String ToString() {
return ( numero + titular + saldo.ToString() ); }
Luego...
CuentaBancaria cuenta = new CtaCte(12,”Juan”);
Console.WriteLine(cuenta);
2c2009
36
A3F
Métodos abstractos (1)
Nunca van a ser invocados
Caso del dibujar de Figura
Además, definen que toda instancia de una subclase
va a poder responder a ese mensaje
Aunque sin definir comportamiento, porque a nivel
de la clase madre no se puede prever
En lenguajes compilados, es también una necesidad
de compilación
2c2009
37
A3F
Métodos abstractos (2)
Corolarios
No tienen implementación
Deben redefinirse
Deben ser virtuales
En Java y C#:
public void abstract dibujar();
Si una clase tiene métodos abstractos debe ser
abstracta
2c2009
38
A3F
Clases internas
Pueden utilizar métodos y atributos privados de su clase
externa (sin relación de herencia)
Pueden ser descendientes de cualquier clase visible de la
clase externa
En una clase descendiente de la externa se puede declarar
una clase interna que descienda de la interna del ancestro
Se usan poco
2c2009
39
A3F
Clases dentro de métodos y
anónimas (Java)
public class Externa {
//...
public void m ( ) {
class Interna extends Base {
// ...
}
Interna i = new Interna ( );
// ...
}
public class Externa {
//...
public Base m( ) {
// ...
return new Base( ) {
// declaración de la
// clase anónima ...
}
}
}
}
2c2009
40
A3F
Manejo de problemas (v1)
public Fraccion (int numerador, int denominador) {
if (denominador == 0)
throw new ArgumentException( );
this.numerador = numerador;
this.denominador = denominador;
}
public Fraccion Dividir (Fraccion y) {
if (y.numerador == 0)
throw new DivideByZeroException( );
int numerador = this.numerador * y.denominador;
int denominador = this.denominador * y.numerador;
return new Fraccion(numerador, denominador);
}
2c2009
41
A3F
Manejo de problemas (v2)
public Fraccion (int numerador, int denominador) {
if (denominador == 0)
throw new FraccionInvalidaException ( );
this.numerador = numerador;
this.denominador = denominador;
}
public Fraccion Dividir (Fraccion y) {
if (y.numerador == 0)
throw new FraccionInvalidaException ( );
int numerador = this.numerador * y.denominador;
int denominador = this.denominador * y.numerador;
return new Fraccion(numerador, denominador);
}
2c2009
42
A3F
Clases de excepciones
¿Qué es FraccionInvalidaException?
Una clase de excepción
Debe derivar de Exception o una derivada
public class FraccionInvalidaException :
System.ApplicationException { }
Lo que se lanza es un objeto, instancia de esa clase
Las jerarquías influyen en la captura:
Se captura cualquier clase derivada
Ojo con el orden de captura
2c2009
43
A3F
Jerarquías de excepciones
(Java)
En .NET todas las excepciones
son “no chequeadas”
2c2009
44
A3F
Excepciones chequeadas
(Java, 1)
Cláusula “throws” obligatoria
public Fraccion dividir (Fraccion y) throws FraccionInvalidaException {
if (y.numerador == 0)
throw new FraccionInvalidaException ( );
int numerador = this.numerador * y.denominador;
int denominador = this.denominador * y.numerador;
return new Fraccion(numerador, denominador);
}
A lo sumo se puede declarar un ancestro
En redefiniciones, mantener y no agregar
Para mantener el polimorfismo: muy molesto
2c2009
45
A3F
Excepciones chequeadas
(Java, 2)
Obligación de capturar (I)
public Fraccion divisionMultiple ( Fraccion [ ] x, Fraccion [ ] y ) {
Fraccion suma = new Fraccion (0, 1);
try {
for (int i = 0; i < 10; i++) {
Fraccion d = x[i].dividir ( y [i] );
suma = suma.sumar(d);
}
} catch (FraccionInvalidaException e) {
System.err.println(“División por cero”);
return new Fraccion (0, 1);
}
return s;
}
2c2009
46
A3F
Excepciones chequeadas
(Java, 3)
Obligación de capturar (II)
public Fraccion divisionMultiple ( Fraccion [ ] x, Fraccion [ ] y )
throws FraccionInvalidaException {
Fraccion suma = new Fraccion (0, 1);
for (int i = 0; i < 10; i++) {
Fraccion d = x[i].dividir( y[i] );
suma = suma.Sumar(d);
}
return s;
}
2c2009
47
A3F
Excepciones chequeadas
(Java, 4)
Obligación de capturar (III)
public Fraccion divisionMultiple ( Fraccion [ ] x, Fraccion [ ] y) {
Fraccion suma = new Fraccion (0, 1);
try {
for (int i = 0; i < 10; i++) {
Fraccion d = x[i].dividir( y[i] );
suma = suma.sumar(d);
}
} catch (FraccionInvalidaException e) { }
return s;
}
2c2009
48
A3F
Lenguajes: enfoques
Excepciones chequeadas
Son más seguras
Molesta tener que capturarlas sí o sí
Limita la redefinición, al no poder agregar nuevas
excepciones
Aunque cumple el principio de substitución
Microsoft diseñó .NET sin excepciones chequeadas
C++ tiene un enfoque mixto
Ojo: Java permite ambas
Aunque es una decisión de diseño
2c2009
49
A3F
Claves
Java y C# son lenguajes de tipos estáticos
La sintaxis deriva de C, pero la semántica no tanto
C# maneja “propiedades”, Java no
Más niveles de visibilidad que en Smalltalk
Herencia implica posibilidades de “casteo hacia arriba”
Polimorfismo por defecto en Java, no en C#
Excepciones chequeadas en Java, no en C#
Mejor soporte para clases y métodos abstractos que en Smalltalk
2c2009
50
A3F
Qué sigue
Interfaces, colecciones, genericidad
Primer parcial
Desarrollo de software y metodología
2c2009
51
A3F
Descargar