Tipos de Datos
Clases
Clase
Mecanismo que
permite definir nuevos tipos de datos
Tipo de Dato
Permite definir qué operaciones son válidas
Tipo de Dato
También permite
definir invariantes
Invariantes
Condiciones que deben
ser ciertas para que un
Tipo de Dato sea correcto
Invariates
- Fracción: no puede tener denominador 0
- Persona: Id no puede ser nulo
- Batalla Naval: Un tablero inicia con 5 barcos
- Etc.
Un correcto uso de Tipos de Datos permite asegurar que un programa es correcto
Métodos
Definen las operaciones que se pueden hacer
sobre un Tipo de Dato
Atributos
Definen la información
que sustentan los métodos
API
El conjunto de métodos públicos de un Tipo de Dato
El API es lo más
importante en un Tipo
de Dato porque es lo que forma un programa
Los atributos son detalles de implementación.
Suelen variar mucho
y eso es bueno.
Encapsulamiento
Permite proteger las invariantes y desacoplar otros tipos de datos de los detalles de implementación
Modificadores
de Acceso
De menor a mayor acceso: private, (package), protected, public
Regla de Oro
Todo debe tener la
menor visibilidad posible.
Objetos
Objeto
Es una instancia
de una clase
Estado
Los valores que tienen
los atributos de un objeto en un instante dado
Una fracción, p.j.,
con estado:
denominador 1,
numerador 2
Constructor
¡La parte más
importante
de una clase!
Constructor
Es el lugar natural para proteger las invariantes
Constructor
¡Valide los parámetros!
public class Fracción {
private int numerador;
private int denominador;
public Fracción(int numerador, int denominador) {
if (denominador == 0) {
throw new IllegalArgumentException();
}
this.numerador = numerador;
this.denominador = denominador;
}
}
public class Persona {
private Cédula cédula;
private Palabra nombre;
private Palabra apellido;
public Persona(Cédula cédula, Palabra nombre, Palabra apellido) {
this.cédula = Objets.requireNonNull(cédula);
this.nombre = Objets.requireNonNull(nombre);
this.apellido = Objets.requireNonNull(apellido);
}
}
Una clase debería tener
al menos un constructor con parámetros.
Entre más, mejor
Mutabilidad
Si un objeto puede
cambiar su estado entonces se dice que el tipo de dato es mutable
public class Fracción {
private int numerador;
private int denominador;
public Fracción(int numerador, int denominador) {
this.numerador = numerador;
this.denominador = denominador;
}
public void inverso() {
int temp = this.numerador;
this.numerador = this.denominador;
this.denominador = temp;
}
public String toString() {
return numerador + "/" + denominador;
}
}
Fracción, versión mutable
Fracción unMedio = new Fracción(1, 2);
unMedio.toString(); // 1/2
unMedio.inverso();
unMedio.toString(); // 2/1
Mutabilidad
Usualmente se produce
en métodos void
Mutabilidad
Es deseable evitarla
al máximo
public class Fracción {
private int numerador;
private int denominador;
public Fracción(int numerador, int denominador) {
this.numerador = numerador;
this.denominador = denominador;
}
public Fracción inverso() {
return new Fracción(denominador, numerador);
}
public String toString() {
return numerador + "/" + denominador;
}
}
Fracción, versión inmutable
Fracción unMedio = new Fracción(1, 2);
unMedio.toString(); // 1/2
unMedio.inverso();
unMedio.toString(); // ¡aún 1/2!
Fracción unMedio = new Fracción(1, 2);
unMedio.toString(); // 1/2
Fracción dos = unMedio.inverso();
unMedio.toString(); // ¡aún 1/2!
dos.toString(); // ¡2/1!
Constructor Vacío
Lleva a mutabilidad y clases que no pueden proteger sus invariantes, facilmente
// no está realmente construído
Fracción unMedio = new Fracción();
unMedio.setNumerador(1); // ya casi
unMedio.setDenominador(2); // ¿ahora si?
Es difícil saber cuándo el objeto está construído
Evite al máximo los constructores vacíos,
los setters y los métodos void en general
No todo debe ser
un JavaBean
Sólo úselos si utiliza un FW o librería que los necesite, como Hibernate o Gson
Single Responsibility Principle - SRP
SRP
Una clase debe tener una sola razón para cambiar
SRP
Un tipo de dato
solo debería realizar operaciones asociadas
con su estado
SRP
Los métodos deberían utilizar la mayoría de atributos
public class Fracción {
private int numerador;
private int denominador;
// código
public Fracción inverso() {
// utiliza todos los atributos!
return new Fracción(denominador, numerador);
}
public static int mcd(int a, int b) {
// no usa ningún atributo :(
// solo depende de los parámetros
return b == 0 ? a : mcd(b, a % b);
}
}
SRP
Todo método que no
utiliza atributos debe ser marcado como static
SRP
Los métodos static usualmente pertenecen a una clase Utilitaria
Clase Utilitaria
Clase sin estado que sólo tiene métodos estáticos
y constantes
SRP
Operaciones que dependan fuertemente del estado
de un objeto o que puedan romper una invariante deben ir en la clase
de ese objeto
public class Fracción {
// código
public Fracción sumar(Fracción otra) {
int MCD = OperacionesAritmética(this.denominador, otra.denominador);
int a = this.denominador / MCD * otra.numerador;
int b = otra.denominador / MCD * this.numerador;
return new Fracción(a + b, MCD);
}
}
SRP
sumar() depende del estado de las fracciones
y puede romper las invariantes, lógicamente debe ser parte de Fracción
Expresividad
¿Cómo modelamos una Persona que tiene cédula, nombre y apellido?
public class Persona {
private String cédula;
private String nombre;
private String apellido;
}
¿Todo es un String?
¿Qué es un String?
A un alto nivel: una secuencia, sin límite
de longitud, de
cualquier caracter
que un computador
pueda interpretar
¿Se parece a una cédula,
un nombre o un apellido?
¡NO!
public class Persona {
private Cédula cédula;
private Nombre nombre;
private Nombre apellido;
}
public class Cédula {
private String número;
public Cédula(String número) {
// puedo forzar invariantes
// debe tener sólo dígitos
// tener entre 8 y 10 dígitos
// también puedo limpiar la
// la representación
this.número = número;
}
}
public class Nombre {
private String nombre;
public Cédula(String nombre) {
// puedo forzar invariantes:
// debe tener letras
// también puedo limpiar la
// la representación
this.nombre = nombre;
}
}
¿Qué tal un libro?
public class Libro {
private String título;
private String isbn;
private String autor;
private String fechaDePublicación;
}
¡Todo es un String!
public class Libro {
private Frase título;
private ISBN isbn;
private NombreCompleto autor;
private Calendar fechaDePublicación;
}
public class Frase {
public String frase;
public Frase(String frase) {
// solo letras, espacios
// signos de puntuación
this.frase = frase;
}
}
public class NombreCompleto {
private Nombre nombre;
private Nombre[] nombresIntermedios;
private Nombre apellido;
}
public class ISBN {
private String isbn;
public ISBN(String isbn) {
// invariantes sobre longitud
// dígitos de verificación
this.isbn = isbn;
}
}
¿Es una fecha de publicación de un
libro un Calendar?
Un Calendar representa
un instante específico
en el tiempo en un territorio específico
Una fecha de publicación es simplemente
la combinación de un
mes y un año
public class Libro {
private Frase título;
private ISBN isbn;
private NombreCompleto autor;
// YearMonth es parte de Java 8
private YearMonth fechaDePublicación;
}
¿Una Carta de una baraja?
Una Carta tiene un
número y un palo
El número solo tiene 13 valores posibles: A, 2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q o K
El palo solo tiene 4 valores posibles: trébol, pica, corazón o diamantes
Un enum representa
un tipo de datos con
un conjunto finito de valores posibles
public enum Número {
AS, DOS, TRES, CUATRO, CINCO,
SEIS, SIETE, OCHO, NUEVE, DIEZ, J, Q, K;
}
public enum Palo {
TRÉBOL, PICA, CORAZÓN, DIAMANTE;
}
public enum Carta {
private Número número;
private Palo palo;
public Carta(Número número, Palo palo) {
this.número = número;
this.palo = palo;
}
}
Carta asCorazones = new Carta(Número.AS, Palo.CORAZÓN);
Carta jotaTrébol = new Carta(Número.J, Palo.TRÉBOL);
Conclusiones
La POO se basa en
la creación de nuevos
tipos de datos y como
se comunican estos
a través de su API
Los tipos de datos protegen sus invariantes mediante
el encapsulamiento
Crear clases inmutables evita todo tipo
de problemas en
los programas
Solo utilice JavaBeans
en clases puntuales
cuando un FW o una
librería lo requiera
SRP: busqué crear tipos
de datos cohesivos
Q&A
La Travesía del Programador: Tipos de Datos
By Carlos Obregón
La Travesía del Programador: Tipos de Datos
La Travesía del Programador comienza con los Tipos de Datos
- 1,835