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(); }