Más Liskov
package com.trifulcas.liskov;
public class DocumentNoLiskov {
public String Content;
// Implementa los dos métodos sin tener en cuenta
// Que clases derivadas pueden no necesitarlos
public void Read() {
System.out.println(Content);
}
public void Write(String content) {
Content = content;
}
}
package com.trifulcas.liskov;
public class ReadOnlyDocumentNoLiskov extends DocumentNoLiskov {
// Al derivar de document pero no implementar write
// Tenemos que lanzar un error
public void Write(String content) {
throw new IllegalArgumentException("Cannot write to a read-only document.");
}
}
DocumentNoLiskov a = new DocumentNoLiskov();
ReadOnlyDocumentNoLiskov b = new ReadOnlyDocumentNoLiskov();
ArrayList<DocumentNoLiskov> lista = new ArrayList<>();
lista.add(a);
lista.add(b);
// No podemos usar Liskov porque ReadOnly no implementa escritura
for (DocumentNoLiskov doc : lista) {
doc.Write("Hola"); // Lanza un error en el documento de solo lectura
}
package com.trifulcas.liskov;
public interface Readable {
public String read();
}
package com.trifulcas.liskov;
public interface Writable {
void write(String content);
}
package com.trifulcas.liskov;
public class EditableDocument implements Readable, Writable {
private String content;
@Override
public void write(String content) {
this.content = content;
}
@Override
public String read() {
return content;
}
}
package com.trifulcas.liskov;
public class ReadOnlyDocument implements Readable {
private String content;
@Override
public String read() {
// TODO Auto-generated method stub
return content;
}
}
EditableDocument e = new EditableDocument();
EditableDocument f = new EditableDocument();
ReadOnlyDocument g = new ReadOnlyDocument();
ReadOnlyDocument h = new ReadOnlyDocument();
ArrayList<Readable> leibles = new ArrayList<>();
ArrayList<Writable> editables = new ArrayList<>();
leibles.add(e);
leibles.add(f);
leibles.add(g);
leibles.add(h);
for (Readable doc : leibles) {
doc.read();
}
editables.add(e);
editables.add(f);
// No podemos añadir un documento que no se puede escribir
// editables.add(g);
for (Writable doc : editables) {
doc.write("ww");
}
Ejemplo Liskov con cuentas corrientes
package com.trifulcas.liskov;
public abstract class BankAcount {
protected double balance;
public BankAcount(double balance) {
super();
this.balance = balance;
}
public void Deposit(double amount) {
balance += amount;
System.out.printf("Deposit: %.2f, Total Amount: %.2f\n", amount, balance);
}
public abstract void Withdraw(double amount);
public double GetBalance() {
return balance;
}
@Override
public String toString() {
return "BankAcount [balance=" + balance + "]";
}
}
package com.trifulcas.liskov;
public class RegularAccount extends BankAcount {
public RegularAccount(double balance) {
super(balance);
// TODO Auto-generated constructor stub
}
@Override
public void Withdraw(double amount) {
if (balance >= amount) {
balance -= amount;
System.out.printf("Withdraw: %.2f, Balance: %.2f\n", amount, balance);
} else {
System.out.printf("Trying to Withdraw: %.2f, Insufficient Funds, Available Funds: %.2f\n", amount, balance);
}
}
}
package com.trifulcas.liskov;
public class FixedAccount extends BankAcount {
public FixedAccount(double balance) {
super(balance);
// TODO Auto-generated constructor stub
}
private boolean termEnded = false; // simplification for the example
@Override
public void Withdraw(double amount) {
if (!termEnded) {
System.out.println("Cannot withdraw from a fixed term deposit account until term ends");
} else if (balance >= amount) {
balance -= amount;
System.out.printf("Withdraw: %.2f, Balance: %.2f\n", amount, balance);
} else {
System.out.printf("Trying to Withdraw: %.2f, Insufficient Funds, Available Funds: %.2f\n", amount, balance);
}
}
}
package com.trifulcas.liskov;
import java.util.ArrayList;
public class Customer {
private String name;
private ArrayList<BankAcount> counts;
public Customer(String name) {
super();
this.name = name;
counts = new ArrayList<>();
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
public void addRegular(int amount) {
counts.add(new RegularAccount(amount));
}
public void addFixed(int amount) {
counts.add(new FixedAccount(amount));
}
public void addAll(int amount) {
// Usando Liskov. Todas las subclases se tratan como la superclase
for (BankAcount ba : counts) {
ba.Deposit(amount);
}
}
@Override
public String toString() {
return "Customer [name=" + name + ", counts=" + counts + "]";
}
}
package com.trifulcas.liskov;
public class TestLiskov {
public static void main(String[] args) {
Customer ana=new Customer("Ana Pi");
ana.addFixed(400);
ana.addRegular(300);
ana.addFixed(300);
System.out.println(ana);
ana.addAll(1000);
System.out.println(ana);
}
}
Propiedades y métodos estáticos
package com.trifulcas.herencia.estatico;
public class Cliente {
private String nombre;
public static double iva=.21;
public Cliente(String nombre) {
super();
this.nombre = nombre;
}
/**
* @return the nombre
*/
public String getNombre() {
return nombre;
}
/**
* @param nombre the nombre to set
*/
public void setNombre(String nombre) {
this.nombre = nombre;
}
@Override
public String toString() {
return "Cliente [nombre=" + nombre + ", iva=" + iva + "]";
}
// Método estático compartido por todas las instancias
// Igual que la propiedad
public static void saludo() {
// Yo desde un método estático no puedo acceder
// a propiedades no estáticas
// Error: System.out.println(nombre);
System.out.println("Hola que tal");
// A las propiedades estáticas, sí
System.out.println(iva);
}
}
package com.trifulcas.herencia.estatico;
public class Utils {
public static String saludo(String nombre) {
return nombre;
}
public static boolean esPrimo(int numero) {
for(int i=2;i<numero;i++) {
if (numero %i==0) {
return false;
}
}
return true;
}
}
Cliente ana = new Cliente("Ana");
Cliente eva = new Cliente("Eva");
Cliente pep = new Cliente("Pep");
// Yo puedo acceder vía la clase porque es estático
Cliente.iva=.10;
// Esto no tiene sentido: Cliente.setNombre("www");
ana.iva=.21;
System.out.println(ana);
System.out.println(eva);
System.out.println(pep);
pep.saludo();
// Al ser un método estático no hace falta que tenga
// una instancia para invocarlo
Cliente.saludo();
// No hace falta: Utils misutilidades=new Utils();
System.out.println(Utils.saludo("Ana"));
System.out.println(Utils.esPrimo(17));
Ejemplos instanceof
ArrayList<Animal> zoo = new ArrayList<>();
Animal mosca = new Insecto();
Perro firulai = new Perro();
Insecto libelula = new Insecto();
firulai.setRaza("Bulldog");
zoo.add(libelula);
zoo.add(mosca);
zoo.add(firulai);
for (Animal animal : zoo) {
animal.hacerRuido();
System.out.println(animal instanceof Perro);
if (animal instanceof Perro) {
((Perro) animal).getRaza();
Perro temp = (Perro) animal;
System.out.println(temp.getRaza());
}
}
ArrayList<IVolar> elementos = new ArrayList<>();
Pelicano p = new Pelicano("Pepe");
Murcielago m = new Murcielago();
Avion a = new Avion();
// Añadir a la lista cualquier clase que implemente IVolar
elementos.add(a);
elementos.add(p);
elementos.add(m);
// Recorrer la lista con un elemento de tipo IVolar
for (IVolar elemento : elementos) {
elemento.volar();
}
// Lista de elementos que implementan INadar
ArrayList<INadar> nadadores = new ArrayList<>();
Delfin f = new Delfin();
nadadores.add(f);
nadadores.add(p);
// Instanceof funciona para los Interfaces
System.out.println(f instanceof INadar); // True
System.out.println(p instanceof IVolar); // True
// Recorrer la lista con un elemento de tipo INadar
// Aquí hago un ArrayList de Object
ArrayList<Object> foo = new ArrayList<>();
// Puedo añadir cualquier objeto de java
foo.add(f);
foo.add(a);
foo.add(p);
foo.add(m);
ArrayList<IVolar> vuelan = new ArrayList<>();
ArrayList<INadar> nadan = new ArrayList<>();
for(Object o:foo) {
if (o instanceof IVolar) {
vuelan.add((IVolar) o);
}
if (o instanceof INadar) {
nadan.add((INadar) o);
}
}
System.out.println(vuelan);
System.out.println(nadan);
Ejemplo clase final
package com.trifulcas.herencia;
public final class Aviso {
private String mensaje;
public Aviso(String mensaje) {
super();
this.mensaje = mensaje;
}
public void alarma() {
System.out.println(mensaje);
}
}
Al ser final, no se puede derivar clases de aquí. Lo siguiente no está permitido:
package com.trifulcas.herencia;
public class AvisoSubClase extends Aviso {
public AvisoSubClase(String mensaje) {
super(mensaje);
}
@Override
public void alarma() {
System.out.println("Mensaje desde una subclase");
}
}
Lo podemos hacer a nivel de método:
package com.trifulcas.herencia;
public class Aviso {
private String mensaje;
public Aviso(String mensaje) {
super();
this.mensaje = mensaje;
}
public final void alarma() {
System.out.println(mensaje);
}
}
Ahora solo se queja en el método, no en la clase:
package com.trifulcas.herencia;
public class AvisoSubClase extends Aviso {
public AvisoSubClase(String mensaje) {
super(mensaje);
}
@Override
public void alarma() {
System.out.println("Mensaje desde una subclase");
}
}
Soluciones ejercicios interfaces y abstractas
package com.trifulcas.herencia.ejercicio;
public abstract class Vehiculo {
private String marca;
private String modelo;
private int anyo;
public Vehiculo(String marca, String modelo, int anyo) {
super();
this.marca = marca;
this.modelo = modelo;
this.anyo = anyo;
}
/**
* @return the marca
*
*/
protected String getMarca() {
return marca;
}
/**
* @return the modelo
*/
public String getModelo() {
return modelo;
}
/**
* @param modelo the modelo to set
*/
public void setModelo(String modelo) {
this.modelo = modelo;
}
/**
* @return the anyo
*/
public int getAnyo() {
return anyo;
}
/**
* @param anyo the anyo to set
*/
public void setAnyo(int anyo) {
this.anyo = anyo;
}
public abstract void mostrarDetalles();
public void encender() {
System.out.println("Vehículo encendido");
}
}
package com.trifulcas.herencia.ejercicio;
public class Coche extends Vehiculo {
private int numeroDePuertas;
public Coche(String marca, String modelo, int anyo, int numeroDePuertas) {
super(marca, modelo, anyo);
this.numeroDePuertas=numeroDePuertas;
}
/**
* @return the numeroDePuertas
*/
public int getNumeroDePuertas() {
return numeroDePuertas;
}
/**
* @param numeroDePuertas the numeroDePuertas to set
*/
public void setNumeroDePuertas(int numeroDePuertas) {
this.numeroDePuertas = numeroDePuertas;
}
@Override
public void mostrarDetalles() {
System.out.println( getMarca()+" - "+getModelo()+" - "+getAnyo()+" - "+getNumeroDePuertas());
}
}
package com.trifulcas.herencia.ejercicio;
public class Motocicleta extends Vehiculo {
public Motocicleta(String marca, String modelo, int anyo, boolean tieneSidecar) {
super(marca, modelo, anyo);
this.tieneSidecar=tieneSidecar;
}
private boolean tieneSidecar;
/**
* @return the tieneSidecar
*/
public boolean getTieneSidecar() {
return tieneSidecar;
}
/**
* @param tieneSidecar the tieneSidecar to set
*/
public void setTieneSidecar(boolean tieneSidecar) {
this.tieneSidecar = tieneSidecar;
}
@Override
public void mostrarDetalles() {
System.out.println( getMarca()+" - "+getModelo()+" - "+getAnyo()+" - "+getTieneSidecar());
}
}
package com.trifulcas.herencia.ejercicio;
public abstract class Empleado {
private String nombre;
private int edad;
private double salario;
public Empleado(String nombre, int edad, double salario) {
super();
this.nombre = nombre;
this.edad = edad;
this.salario = salario;
}
/**
* @return the nombre
*/
public String getNombre() {
return nombre;
}
/**
* @param nombre the nombre to set
*/
public void setNombre(String nombre) {
this.nombre = nombre;
}
/**
* @return the edad
*/
public int getEdad() {
return edad;
}
/**
* @param edad the edad to set
*/
public void setEdad(int edad) {
this.edad = edad;
}
/**
* @return the salario
*/
public double getSalario() {
return salario;
}
/**
* @param salario the salario to set
*/
public void setSalario(double salario) {
this.salario = salario;
}
public abstract double calcularBonificacion();
public void mostrarDetalles() {
System.out.println(getNombre()+" - "+getEdad()+" - "+getSalario());
}
}
package com.trifulcas.herencia.ejercicio;
public class EmpleadoMedioTiempo extends Empleado {
private int horasTrabajadas;
public EmpleadoMedioTiempo(String nombre, int edad, double salario, int horasTrabajadas) {
super(nombre, edad, salario);
this.horasTrabajadas = horasTrabajadas;
}
/**
* @return the horasTrabajadas
*/
public int getHorasTrabajadas() {
return horasTrabajadas;
}
/**
* @param horasTrabajadas the horasTrabajadas to set
*/
public void setHorasTrabajadas(int horasTrabajadas) {
this.horasTrabajadas = horasTrabajadas;
}
@Override
public double calcularBonificacion() {
return getHorasTrabajadas() * 1.2;
}
public void mostrarDetalles() {
System.out.println(getNombre() + " - " + getEdad() + " - " + getSalario() + " - " + getHorasTrabajadas());
}
}
package com.trifulcas.herencia.ejercicio;
public class EmpleadoTiempoCompleto extends Empleado {
private double bono;
public EmpleadoTiempoCompleto(String nombre, int edad, double salario, double bono) {
super(nombre, edad, salario);
this.bono=bono;
}
/**
* @return the bono
*/
public double getBono() {
return bono;
}
/**
* @param bono the bono to set
*/
public void setBono(double bono) {
this.bono = bono;
}
@Override
public double calcularBonificacion() {
return bono;
}
@Override
public void mostrarDetalles() {
System.out.println(getNombre()+" - "+getEdad()+" - "+getSalario()+" - "+getBono());
}
}
package com.trifulcas.herencia.ejercicio;
public interface MetodoPago {
void procesarPago(double monto);
void mostrarDetalles();
}
package com.trifulcas.herencia.ejercicio;
public class TarjetaCredito implements MetodoPago {
private String numeroTarjeta;
private String titular;
private String fechaExpiracion;
public TarjetaCredito(String numeroTarjeta, String titular, String fechaExpiracion) {
super();
this.numeroTarjeta = numeroTarjeta;
this.titular = titular;
this.fechaExpiracion = fechaExpiracion;
}
@Override
public void procesarPago(double monto) {
System.out.println("Procesando el pago de "+monto);
}
@Override
public void mostrarDetalles() {
System.out.println(numeroTarjeta+" - "+titular+" - "+fechaExpiracion);
}
}
package com.trifulcas.herencia.ejercicio;
public class Paypal implements MetodoPago {
private String email;
public Paypal(String email) {
super();
this.email = email;
}
@Override
public void procesarPago(double monto) {
System.out.println("Procesando el pago PAYPAL de "+monto);
}
@Override
public void mostrarDetalles() {
System.out.println(email);
}
}
package com.trifulcas.herencia.ejercicio;
public class TransferenciaBancaria implements MetodoPago {
private String numeroCuenta;
private String banco;
@Override
public void procesarPago(double monto) {
System.out.println("Procesando pago Transferencia "+monto);
}
@Override
public void mostrarDetalles() {
System.out.println(numeroCuenta+" - "+banco);
}
}
Unidades CSS la guía definitiva
Clase abstracta e interfaces todo junto
package com.trifulcas.herencia.interfaces;
public abstract class Animal {
private String nombre;
public Animal(String nombre) {
super();
this.nombre = nombre;
}
/**
* @return the nombre
*/
public String getNombre() {
return nombre;
}
/**
* @param nombre the nombre to set
*/
public void setNombre(String nombre) {
this.nombre = nombre;
}
@Override
public String toString() {
return "Animal [nombre=" + nombre + "]";
}
public abstract void hacerRuido();
}
package com.trifulcas.herencia.interfaces;
public class Pato extends Animal implements IVolar, INadar, ICorrer {
public Pato(String nombre) {
super(nombre);
// TODO Auto-generated constructor stub
}
// Lo implemento porque implemento el interfaz IVolar
@Override
public void volar() {
System.out.println("Un patito volando");
}
// Lo implemento porque implemento el interfaz ICorrer
@Override
public void correr() {
System.out.println("Un patito corriendo");
}
// Lo implemento porque implemento el interfaz INadar
@Override
public void nadar() {
System.out.println("Un patito nadando");
}
// Lo tengo que implementar porque lo tiene la clase madre
// Animal
@Override
public void hacerRuido() {
System.out.println("Cua cua");
}
}
package com.trifulcas.herencia.interfaces;
public class Perro extends Animal implements ICorrer, INadar {
public Perro(String nombre) {
super(nombre);
// TODO Auto-generated constructor stub
}
// Lo implemento porque implemento el interfaz ICorrer
@Override
public void correr() {
System.out.println("Un perrito corriendo");
}
// Lo implemento porque implemento el interfaz INadar
@Override
public void nadar() {
System.out.println("Un perrito nadando");
}
// Método abstracto de la clase madre
@Override
public void hacerRuido() {
System.out.println("Guau guau");
}
}
Ejemplos interfaces
package com.trifulcas.herencia.interfaces;
// El interface lo creo con la palabra clave interface
public interface IVolar {
// Dentro del interface defino funciones SIN IMPLEMENTACION
// Igual que los métodos abstractos son una obligación de implementar la función
// Un interface es como un contrato
public void volar();
}
package com.trifulcas.herencia.interfaces;
public interface INadar {
public void nadar();
}
package com.trifulcas.herencia.interfaces;
// En la clase para implementar un interface utilizamos implements
public class Pelicano implements IVolar, INadar{
public Pelicano() {
// TODO Auto-generated constructor stub
}
@Override
public void volar() {
System.out.println("Un majestuoso pelícano surcando el cielo");
}
@Override
public void nadar() {
System.out.println("Un pelícano nadando");
}
}
package com.trifulcas.herencia.interfaces;
public class Murcielago implements IVolar {
public Murcielago() {
// TODO Auto-generated constructor stub
}
@Override
public void volar() {
System.out.println("Un murciélago volando en la noche");
}
}
package com.trifulcas.herencia.interfaces;
public class Avion implements IVolar {
public Avion() {
// TODO Auto-generated constructor stub
}
@Override
public void volar() {
System.out.println("Un avión surcando raudo las nubes");
}
}
package com.trifulcas.herencia.interfaces;
public class Delfin implements INadar {
@Override
public void nadar() {
System.out.println("Un esbelto delfín surcando las procelosas aguas del océano");
}
}
// Lista de elementos que implementan IVolar
ArrayList<IVolar> elementos=new ArrayList<>();
Pelicano p=new Pelicano();
Murcielago m=new Murcielago();
Avion a=new Avion();
// Añadir a la lista cualquier clase que implemente IVolar
elementos.add(a);
elementos.add(p);
elementos.add(m);
// Recorrer la lista con un elemento de tipo IVolar
for(IVolar elemento:elementos) {
elemento.volar();
}
// Lista de elementos que implementan INadar
ArrayList<INadar> nadadores=new ArrayList<>();
Delfin f=new Delfin();
nadadores.add(f);
nadadores.add(p);
// Recorrer la lista con un elemento de tipo INadar
for(INadar elemento:nadadores) {
elemento.nadar();
}