Repaso OOP 5: Herencia

package com.trifulcas.repaso.oop;

// La herencia se implementa con extends
// AlumnoIntercambio deriva de Alumno
// Alumno es la superclase o clase madre 
// y AlumnoIntercambio la clase hija o derivada o subclase
public class AlumnoIntercambio extends Alumno {

	private String paisOrigen;
	
	public String getPaisOrigen() {
		return paisOrigen;
	}

	public void setPaisOrigen(String paisOrigen) {
		this.paisOrigen = paisOrigen;
	}

	public AlumnoIntercambio(String nombre, int nota, String email) {
		super(nombre, nota, email);
		
	}
	public void saludo() {
		// Recordad que las propiedades private no son visibles desde
		// la clase derivada, esto da error
		// System.out.println("hola "+nombre);
		System.out.println("hola "+getNombre());
	}
	// Sobreescribir los métodos que heredo de la clase madre
	// Y tener otra implementación, en este caso el toString
	@Override
	public String toString() {
		// La palabra clave super hace referencia a la clase madre
		// Aquí lo usamos para acceder al método toString de Alumno
		return "AlumnoIntercambio [paisOrigen=" + paisOrigen + ", " + super.toString() + "]";
	}

	

}

package com.trifulcas.repaso.oop;

public class TestOOP {

	public static void main(String[] args) {
		
		AlumnoIntercambio john=new AlumnoIntercambio("John",6,"eee");
		// Al derivar de alumno John tiene todas las propiedades
		// Y métodos que tiene alumno
		System.out.println(john.getAprobado());
		john.setMail("pepe@pee.com");
		System.out.println(john);
		// La subclase puede tener sus propios métodos y propiedades
		john.setPaisOrigen("Bélgica");
		System.out.println(john);
		Alumno eva=new Alumno("Eva",6,"wwww");
		// La superclase no tiene las propiedades de las subclases
		// Esto da error eva.getPaisOrigen()
		
		// Yo puedo definir una variable como la clase madre
		// Pero instanciarla como la clase hija
		// Para qué? Polimorfismo
		Alumno pep=new AlumnoIntercambio("pep",4,"ww");
	}

}

Repaso OOP 4: static

package com.trifulcas.repaso.oop;

// Las clases las definimos con la palabra clave class
// Y el nombre de la clase primera en mayúsculas
// Recordad que en java el nombre del archivo y la clase debe ser el mismo

public class Alumno {

	// Lo habitual es que todas las propiedades sean private
	// Para evitar que se puedan modificar desde el exterior
	private String nombre;

	private int nota;

	private String mail;
	
	// Las propiedades o métodos estáticos solo existen una vez
	// (es decir, hay una única instancia para todos los objetos de esta clase)
	// Podemos acceder a ellos sin instanciar un objeto
	// La información es compartida por todos
	private static int notaCorte=5;

	// El constructor es la manera como se construye la instancia
	// de la clase. Es el punto de entrada
	// Podemos tener parámetros o no y podemos tener sobrecargas

	// Un ejemplo típico sería este. Usamos todas las propiedades

	public Alumno(String nombre, int nota, String email) {
		// La palabra clave this hace referencia al propio objeto
		// La usamos para desambiguar entre el nombre de los parámetros
		// y de las propiedades de la clase
		this.nombre = nombre;
		this.nota = nota;
		// Aquí no hace falta desambiguar porque se llaman diferente
		mail = email;
	}

	// Yo los constructores los puedo sobrecargar
	public Alumno(String nombre, int nota) {
		this.nombre = nombre;
		this.nota = nota;
		mail = "No tiene";
		
		// this(nombre,nota,"No tiene")
	}
	
	// Si yo hago sobrecarga lo suyo es que llamemos al otro constructor
	public Alumno(String nombre) {
		/* Si yo quiero hacer esto
		this.nombre = nombre;
		this.nota = 0;
		mail = "No tiene";
		Lo mejor es hacer esto:
		*/
		this(nombre,0,"No tiene"); // this hace referencia al constructor
	}

	public String getNombre() {
		return nombre;
	}

	public void setNombre(String nombre) {
		this.nombre = nombre;
	}

	public int getNota() {
		return nota;
	}

	public void setNota(int nota) {
		this.nota = nota;
	}

	public String getMail() {
		return mail;
	}

	public void setMail(String mail) {
		this.mail = mail;
	}
	public boolean getAprobado() {
		// La nota de corte es la misma para todos los objetos
		return nota>=notaCorte;
	}
	
	
	public static int getNotaCorte() {
		return notaCorte;
	}

	public static void setNotaCorte(int notaCorte) {
		Alumno.notaCorte = notaCorte;
	}

	@Override
	public String toString() {
		return "Alumno [nombre=" + nombre + ", nota=" + nota + ", mail=" + mail + "]";
	}

	
}

package com.trifulcas.repaso.oop;

public class Utils {
	// Si mi clase tiene métodos estáticos
	public static boolean esPrimo(int numero) {
		for (int i = 2; i < numero; i++) {
			if (numero % i == 0) {
				return false;
			}
		}
		return true;
	}

	public static boolean esPar(int numero) {
		return numero % 2 == 0;
	}
}

package com.trifulcas.repaso.oop;

import java.util.Arrays;

public class TestOOP {

	public static void main(String[] args) {
		
		Alumno ana=new Alumno("Ana",7,"ana@ana.com");
		System.out.println(ana.getNotaCorte());
		// Si yo cambio el valor de la nota de corte
		ana.setNotaCorte(7);
		Alumno eva = new Alumno("Eva",6);
		// La cambio para todos los objetos
		System.out.println(eva.getNotaCorte());
		
		// Puedo acceder sin instanciar el objeto
		Alumno.setNotaCorte(8);
		System.out.println(eva.getNotaCorte());
		System.out.println(ana.getNotaCorte());
		
		Alumno[] clase=new Alumno[10];
		// Creando 10 alumnos
		for(int i=0;i<10;i++) {
			clase[i]=new Alumno("Alumno"+i,i);
		}
		System.out.println(Arrays.toString(clase));
		
		// Yo puedo usar los métodos estáticos de una clase sin necesidad
		// de instanciar un objeto de esa clase
		System.out.println(Utils.esPar(10));
		System.out.println(Utils.esPrimo(17));
		// Esto no es necesario
		Utils foo=new Utils();
		System.out.println(foo.esPar(8));
	}

}

Repaso OOP 3: Constructores

package com.trifulcas.repaso.oop;

// Las clases las definimos con la palabra clave class
// Y el nombre de la clase primera en mayúsculas
// Recordad que en java el nombre del archivo y la clase debe ser el mismo

public class Alumno {

	// Lo habitual es que todas las propiedades sean private
	// Para evitar que se puedan modificar desde el exterior
	private String nombre;

	private int nota;

	private String mail;

	// El constructor es la manera como se construye la instancia
	// de la clase. Es el punto de entrada
	// Podemos tener parámetros o no y podemos tener sobrecargas

	// Un ejemplo típico sería este. Usamos todas las propiedades

	public Alumno(String nombre, int nota, String email) {
		// La palabra clave this hace referencia al propio objeto
		// La usamos para desambiguar entre el nombre de los parámetros
		// y de las propiedades de la clase
		this.nombre = nombre;
		this.nota = nota;
		// Aquí no hace falta desambiguar porque se llaman diferente
		mail = email;
	}

	// Yo los constructores los puedo sobrecargar
	public Alumno(String nombre, int nota) {
		this.nombre = nombre;
		this.nota = nota;
		mail = "No tiene";
		
		// this(nombre,nota,"No tiene")
	}
	
	// Si yo hago sobrecarga lo suyo es que llamemos al otro constructor
	public Alumno(String nombre) {
		/* Si yo quiero hacer esto
		this.nombre = nombre;
		this.nota = 0;
		mail = "No tiene";
		Lo mejor es hacer esto:
		*/
		this(nombre,0,"No tiene"); // this hace referencia al constructor
	}

	public String getNombre() {
		return nombre;
	}

	public void setNombre(String nombre) {
		this.nombre = nombre;
	}

	public int getNota() {
		return nota;
	}

	public void setNota(int nota) {
		this.nota = nota;
	}

	public String getMail() {
		return mail;
	}

	public void setMail(String mail) {
		this.mail = mail;
	}

}

package com.trifulcas.repaso.oop;

public class TestOOP {

	public static void main(String[] args) {
		
		// Como el constructor de Alumno tiene parámetros
		// Ahora tenemos que pasar los valores que nos piden
		// Cada vez que hagamos una instancia del objeto
		Alumno ana=new Alumno("Ana",7,"ana@ana.com");
		
		// Como tengo sobrecargado el constructor puedo llamarlo
		// solo con dos parámetros
		Alumno eva = new Alumno("Eva",6);
		
		
	}

}

Repaso OOP 2: getters y setters

package com.trifulcas.repaso.oop;

// Las clases las definimos con la palabra clave class
// Y el nombre de la clase primera en mayúsculas
// Recordad que en java el nombre del archivo y la clase debe ser el mismo

public class Alumno {

	// Lo habitual es que todas las propiedades sean private
	// Para evitar que se puedan modificar desde el exterior
	private String nombre;

	private int nota;

	private String mail;
	
	private String password;

	// Si no se pueden modificar desde el exterior no servirían para nada
	// Las podemos modificar pero desde setters y getters
	// Son métodos públicos que nos sirven para obtener el valor o
	// modificarlo pero que son una capa entre mis propiedades
	// y el exterior

	// password es  una propiedad de solo escritura
	/**
	 * @param password the password to set
	 */
	public void setPassword(String password) {
		this.password = password;
	}

	/**
	 * @return the nombre
	 */
	public String getNombre() {
		return nombre;
	}

	/**
	 * @param nombre the nombre to set
	 */
	public void setNombre(String nombre) {
		this.nombre = nombre;
	}

	/**
	 * @return the nota
	 */
	public int getNota() {
		return nota;
	}

	/**
	 * @param nota the nota to set
	 */
	public void setNota(int nota) {
		// Como yo tengo un setter puedo comprobar los valores
		// antes de ponerlos
		if (nota>0 && nota <=10) {
			this.nota = nota;
		}
		
	}

	// Mail es de solo lectura
	/**
	 * @return the mail
	 */
	public String getMail() {
		return mail;
	}
	
	// Esto es una propiedad virtual
	public boolean getAprobado() {
		return nota>=5;
	}

	

}
package com.trifulcas.repaso.oop;

public class TestOOP {

	public static void main(String[] args) {
		
		Alumno ana=new Alumno();
		// Pongo los valores con set
		ana.setNombre("Ana");
		ana.setNota(8);
		// Puedo poner password
		ana.setPassword("1234");
		// Obtengo con get
		System.out.println(ana.getNombre());
		// Pero no leerlo
		// System.out.println(ana.getPassword());
		// No puedo poner el mail
		// ana.setMail("sss");
		System.out.println(ana.getMail());
		// Yo no sé si esa propiedad existe de verdad o no
		// Ni me importa: La idea es que de una clase solo conocemos
		// los métodos que publicamos. Su organización interna
		// No nos preocupa
		System.out.println(ana.getAprobado());
	}

}

Repaso OOP 1

package com.trifulcas.repaso.oop;

// Las clases las definimos con la palabra clave class
// Y el nombre de la clase primera en mayúsculas
// Recordad que en java el nombre del archivo y la clase debe ser el mismo

public class Alumno {
	
	// Una clase tendrá propiedades, que son variables encapsuladas dentro
	// de la clase. Las propiedades tienen modificadores
	
	// public: todo el mundo puede acceder a la propiedad
	public String nombre;
	
	// protected: solo desde la propia clase, paquete y derivadas
	protected int nota;
	
	// private: solo desde la propia clase
	private String mail;
	
	// Puedo tener métodos
	// Que tienen los mismos modificadores
	// Dentro de los métodos de una clase puedo acceder a las
	// propiedades de la clase
	public void saludo() {
		System.out.println("Hola "+nombre+" que tal");
	}

}

package com.trifulcas.repaso.oop;

public class TestOOP {

	public static void main(String[] args) {
		
		// La clase es la 'plantilla' lo que uso son las instancias (objetos)
		Alumno ana=new Alumno();
		
		
		// Accedo porque es público
		ana.nombre="Ana";
		// Accedo porque es protected y estoy en el mismo paquete
		ana.nota=5;
		// No puedo acceder porque es privada
		// ana.mail="www";
		ana.saludo();
		
		// esta es otra instancia de la clase con sus propios valores
		// Si yo llamo a saludo utiliza los valores de su instancia
		Alumno eva=new Alumno();
		eva.nombre="Eva";
		eva.saludo();
	}

}

Ejercicio cartas

package com.trifulcas.cartas;

public abstract class Carta {
	private String palo;
	private int numero;
	
	public Carta(String palo, int numero) {
		this.palo = palo;
		this.numero = numero;
	}
	/**
	 * @return the palo
	 */
	public String getPalo() {
		return palo;
	}
	/**
	 * @param palo the palo to set
	 */
	public void setPalo(String palo) {
		this.palo = palo;
	}
	/**
	 * @return the numero
	 */
	public int getNumero() {
		return numero;
	}
	/**
	 * @param numero the numero to set
	 */
	public void setNumero(int numero) {
		this.numero = numero;
	}
	
	public abstract int getValor();
	
	@Override
	public String toString() {
		return numero+" de "+palo;
	}
	
	
}

package com.trifulcas.cartas;

public class Espanyola extends Carta {

	public Espanyola(String palo, int numero) {
		super(palo, numero);
	}

	@Override
	public int getValor() {
		if (getNumero()>=10) {
			return 10;
		}
		return getNumero();
	}

}

package com.trifulcas.cartas;

public class Francesa extends Carta {

	public Francesa(String palo, int numero) {
		super(palo, numero);
		// TODO Auto-generated constructor stub
	}

	@Override
	public int getValor() {
		// TODO Auto-generated method stub
		return getNumero();
	}

}

package com.trifulcas.cartas;

import java.util.ArrayList;
import java.util.List;

public class Baraja {
	List<Carta> cartas;
	public Baraja() {
		cartas=new ArrayList<>();
	}
	public void addCarta(Carta carta) {
		cartas.add(carta);
	}
	public int totalValor() {
		int total=0;
		for(Carta carta:cartas) {
			total+=carta.getValor();
		}
		return total;
	}
}

package com.trifulcas.cartas;

public class TestCartas {

	public static void main(String[] args) {
		Carta e=new Francesa("Diamantes",7);
		System.out.println(e);
		Carta f=new Espanyola("Bastos",12);
		System.out.println(f);
		Baraja b=new Baraja();
		b.addCarta(f);
		b.addCarta(e);
		System.out.println(b.totalValor());
	}

}

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