27
Dec 16

Pildoritas de POO y Java: Polimorfismo

pildoras poo java
Llevo casi desde que comencé con las pildoritas de POO anunciando que "el polimorfismo va a llegaaaaar" y nada, que no llegaba...¡hasta hoy!

El polimorfismo va muy ligado a la herencia, y se apoya en ella para poder generalizar comportamientos de diferentes clases, como si de una se tratara, siendo para nosotros transparente su tipo, siempre y cuando éste herede de una clase Padre común que define la funcionalidad generalizada.

Polimorfismo

El Polimorfismo es el envío de mensajes a objetos de tipos diferentes utilizando la misma sintaxis. En lenguajes con un sistema de tipos dinámicos, es decir, que una variable puede contener todo tipo de valores y su tipo se setea en tiempo de ejecución. No es necesario el uso de herencia para aplicar el polimorfismo pero en lenguajes fuertemente tipados como Java es necesario utilizar una clase común padre de la cual heredarán todos los objetos polimórficos.

Por ejemplo, basándonos en el ejemplo de nuestra anterior pildorita de Herencia, las clases Profesor y Alumno heredan de Persona varios métodos comunes, como el método toString, que además reimplementan de forma específica cada clase hijo a través de la anotación @Override.

Ahora imaginemos que tenemos un método auxiliar en nuestra aplicación que se dedica a mostrar los datos por pantalla de cualquier persona vinculada a la Escuela, Universidad...¿Cómo lo haríamos de forma general utilizando polimorfismo?

public void mostrarDatos() {
		Profesor profe1 = new Profesor(1, "Antonio", "Brena", "1111111K", 52, "M");
		Profesor profe2 = new Profesor(2, "Alicia", "Hernandez", "2222222K", 45, "F");
		Alumno alumno1 = new Alumno(1, "Mar", "Millan", "44444444K", 29, "F");
		Persona trabajador1 = new Persona("Francisco", "García", "33333333K", 39, "M");
		
		List<Persona> lsPersonas = new ArrayList<Persona>();
		lsPersonas.add(profe1);
		lsPersonas.add(profe2);
		lsPersonas.add(alumno1);
		lsPersonas.add(trabajador1);

		for (Persona per : lsPersonas) {
			System.out.println(per.toString());
		}		
	}

El resultado de ejecutar este método es el siguiente:

DATOS DEL PROFESOR:
Nombre: Antonio
Apellidos: Brena
DNI: 1111111K
Edad: 52
Sexo: M

DATOS DEL PROFESOR:
Nombre: Alicia
Apellidos: Hernandez
DNI: 2222222K
Edad: 45
Sexo: F

DATOS DEL ALUMNO:
Nombre: Mar
Apellidos: Millan
DNI: 44444444K
Edad: 29
Sexo: F

DATOS DE LA PERSONA:
Nombre: Francisco
Apellidos: García
DNI: 33333333K
Edad: 39
Sexo: M

Como se puede observar, para nosotros es indiferente el tipo del objeto que estemos invocando, ya que sabemos que todos esos objetos al heredar de la clase padre Persona tendrán obligatoriamente el método toString. Así mismo, si uno de esos objetos tiene una implementación propia de dicho método, ejecutará la implementación especifica de forma transparente para nosotros.

Aquellos lenguajes que tengan interfaces (como es el caso de Java), pueden también implementar el polimorfismo utilizando este recurso, lo que se conoce como composición de objetos. Esta alternativa se considera mejor práctica a la hora de aplicar polimorfismo que el uso de herencia, ya que este solución sólo obliga a que las diferentes clases compartan el tipo y obligatoriedad de implementar los métodos del interfaz, pero no se comparten comportamientos ni atributos. Pero, ¿qué es una interfaz?

Interfaces y Clases Abstractas

Cuando queremos unificar atributos y métodos en una clase padre, como hemos hecho en la clase Persona, pero no queremos que ésta sea instanciable, crearíamos nuestra clase Persona como clase abstracta:

public abstract class Persona {
	 
    private String nombre;
    private String apellidos;
    private String dni;
    private Integer edad;
    private String sexo;
    
    Persona() {
    	super();
    }
    
    public Persona(String nombre, String apellidos, String dni, Integer edad, String sexo) {
    	super();
    	this.nombre = nombre;
    	this.apellidos = apellidos;
    	this.dni = dni;
    	this.edad = edad;
    	this.sexo = sexo;
    }
    
    public String getNombre() {
        return nombre;
    }
 
    public void setNombre(String nombre) {
        this.nombre = nombre;
    }
 
    public String getApellidos() {
        return apellidos;
    }
 
    public void setApellidos(String apellidos) {
        this.apellidos = apellidos;
    }
 
    public String getDni() {
        return dni;
    }
 
    public void setDni(String dni) {
        this.dni = dni;
    }
 
    public Integer getEdad() {
        return edad;
    }
 
    public void setEdad(Integer edad) {
        this.edad = edad;
    }
 
    public String getSexo() {
        return sexo;
    }
 
    public void setSexo(String sexo) {
        this.sexo = sexo;
    }
    
    @Override 
    public String toString() {
        String nuevalinea = System.getProperty("line.separator");
        String resultado = "DATOS DE LA PERSONA: " + nuevalinea + 
                "Nombre: " + this.getNombre() + nuevalinea + 
                "Apellidos: " + this.getApellidos() + nuevalinea + 
                "DNI: " + this.getDni() + nuevalinea +
                "Edad: " + this.getEdad() + nuevalinea +
                "Sexo: " + this.getSexo() + nuevalinea;
 
        return resultado;
    }
    
	@Override
	public boolean equals(Object object) {
		final Persona aux = (Persona) object;
		if (this == object)
	           return true;
		else if (object == null)
	           return false;
		else if (getClass() != object.getClass())
	           return false;
		else if (this.dni.equals(aux.getDni())) {
			return true;
		} else {
			return false;
		}
	}

     public abstract void metodoAbstracto();
}

Por tanto, en nuestro anterior ejemplo tendríamos un error al crear el objeto Persona trabajador1, ya que, como hemos dicho, las clases abstractas no pueden ser instanciadas:

También podemos añadir métodos abstractos. Un ejemplo de ello es el último método que hemos creado en el ejemplo de la clase abstracta Persona, el método metodoAbstracto(), que como se puede observar siquiera tiene cuerpo. Si creamos un método abstracto estaremos obligados a definir la implementación de dicho método en las clases hijas.

¿Y qué es una interfaz? Pues una clase completamente abstracta, es decir, una clase en la que no se implementan métodos, ni hay atributos, excepto aquellos que sean estáticos y/o constantes.

Los interfaces tienen como finalidad definir la forma y comportamiento de una clase.

Por ejemplo, podríamos tener una interfaz IMamifero, que implemente Persona:

public interface IMamifero {
	public void crecer();
	public void reproducirse();
	public void morir();
}

Para que nuestra clase implemente este interfaz, lo indicaremos a través de la palabra reservada implements.

Al hacer esto, como se puede ver en la anterior imagen, tendremos un error en la mayoría de entornos que nos indicará que tenemos que implementar forzosamente los métodos definidos en el interfaz IMamifero:

public class Persona implements IMamifero {
	 
    private String nombre;
    private String apellidos;
    private String dni;
    private Integer edad;
    private String sexo;
    
    Persona() {
    	super();
    }
    
    public Persona(String nombre, String apellidos, String dni, Integer edad, String sexo) {
    	super();
    	this.nombre = nombre;
    	this.apellidos = apellidos;
    	this.dni = dni;
    	this.edad = edad;
    	this.sexo = sexo;
    }
    
    public String getNombre() {
        return nombre;
    }
 
    public void setNombre(String nombre) {
        this.nombre = nombre;
    }
 
    public String getApellidos() {
        return apellidos;
    }
 
    public void setApellidos(String apellidos) {
        this.apellidos = apellidos;
    }
 
    public String getDni() {
        return dni;
    }
 
    public void setDni(String dni) {
        this.dni = dni;
    }
 
    public Integer getEdad() {
        return edad;
    }
 
    public void setEdad(Integer edad) {
        this.edad = edad;
    }
 
    public String getSexo() {
        return sexo;
    }
 
    public void setSexo(String sexo) {
        this.sexo = sexo;
    }
    
    @Override 
    public String toString() {
        String nuevalinea = System.getProperty("line.separator");
        String resultado = "DATOS DE LA PERSONA: " + nuevalinea + 
                "Nombre: " + this.getNombre() + nuevalinea + 
                "Apellidos: " + this.getApellidos() + nuevalinea + 
                "DNI: " + this.getDni() + nuevalinea +
                "Edad: " + this.getEdad() + nuevalinea +
                "Sexo: " + this.getSexo() + nuevalinea;
 
        return resultado;
    }
    
	@Override
	public boolean equals(Object object) {
		final Persona aux = (Persona) object;
		if (this == object)
	           return true;
		else if (object == null)
	           return false;
		else if (getClass() != object.getClass())
	           return false;
		else if (this.dni.equals(aux.getDni())) {
			return true;
		} else {
			return false;
		}
	}

	@Override
	public void crecer() {
		System.out.println("Crece");
		
	}

	@Override
	public void reproducirse() {
		System.out.println("Fornicia");
		
	}

	@Override
	public void morir() {
		System.out.println("R.I.P.");	
	}
}

Al hacer esto, ya sí que podremos ejecutar nuestra aplicación sin errores y, si queremos, hacer polimorfismo con los métodos definidos por la interfaz:

Profesor profe1 = new Profesor(1, "Antonio", "Brena", "1111111K", 52, "M");
		Profesor profe2 = new Profesor(2, "Alicia", "Hernandez", "2222222K", 45, "F");
		Alumno alumno1 = new Alumno(1, "Mar", "Millan", "44444444K", 29, "F");
		Persona trabajador1 = new Persona("Francisco", "García", "33333333K", 39, "M");
		
		List<Persona> lsPersonas = new ArrayList<Persona>();
		lsPersonas.add(profe1);
		lsPersonas.add(profe2);
		lsPersonas.add(alumno1);
		lsPersonas.add(trabajador1);

		for (Persona per : lsPersonas) {
			per.reproducirse();
		}

Consola:

Fornicia
Fornicia
Fornicia
Fornicia

Como veis, el Polimorfismo no es más que el uso más potente de la herencia, pero no es, ni mucho menos, complejo, al igual que tampoco lo son las ideas de clase abstracta e interfaz una vez se entiende el concepto general de Herencia.

Así que nada, si habéis seguido estas pildoritas al pie de la letra podemos ya afirmar (con extremada timidez, eso sí) que comprendéis y entendéis las bases de lo que es la Programación Orientada a Objetos. A partir de ahora, sólo necesitaréis tiempo y práctica para poder desarrollar cualquier aplicación que deseéis con este paradigma y, eso sí, teniendo claros los conceptos fundamentales que os harán desarollar como las personitas, y no como muchos: con los pies.

Y aunque ésta sí será nuestra última pildorita de POO, ni mucho menos será la última de Java. En las próximas semanas os hablaré de las excepciones (un concepto de Java que escapa a la POO pero fundamental a la hora de programar y realizar un correcto tratamiento de errores) y a partir de ahí, ya se verá. Tenía pensado hacer un programa básico como ejemplo resumen de todo lo que hemos visto, y tras esto, seguir entrando en chicha con conceptos de programación más avanzados.

Índice de Pildoritas

Share
20
Dec 16

Pildoritas de POO y Java: Herencia

pildoras poo java
Como ya dejé entrever en anteriores posts de esta serie de artículos, la pildorita de hoy era la madre de todos los corderos. En ella veríamos un concepto fundamental en POO, la Herencia, y el Polimorfismo, un potente recurso que nos servirá para que la herencia adquiera su máximo potencial a partir de la sobrecarga.

De nuevo del dicho al hecho hay un trecho, y dejo patente una vez más lo noob que soy aún en el terreno de los manuales y tutoriales: La segunda parte de la pildorita, el Polimorfismo, al final va a tener su propio post dedicado, ya que se me iba a ir de las malos su extensión y ya se sabe que mejor separar en trocitos cortos, abarcables y fácilmente comprensibles, que en tochos insufribles y con mil ideas de golpe.

Así que nada, tendréis que esperar a la próxima semana para saber que es eso del Polimorfismo.

En fin, al lío.

Herencia

La herencia tiene como meta la extensión y reutilización de código por lo que se utiliza cuando varias clases tienen funcionalidades comunes, en cuyo caso éstas pueden heredar de una clase padre la funcionalidad común.

Por ejemplo, si volvemos a la imagen de la pildorita de introducción a POO, todas las entidades de la imagen son mamíferos, es decir, todos ellos caminan y maman, no obstante, una Persona podrá, por ejemplo, plantearse el sentido de la vida, mientras un Delfín (que sepamos) no. Así mismo, aunque tanto el Delfín como el Humano pueden desplazarse, uno lo hace nadando con su aleta, mientras otro caminando sobre sus dos piernas, por lo que, aunque sus funcionalidad es igual, se implementa de distinta forma.

mamiferos

Para implementar la herencia entre clases en Java se utiliza la palabra reservada extends. Así mismo, veremos por primera vez una anotación, una muy importante a la hora de utilizar herencia, @Override, y la palabra reservada super.

Para entender mejor la herencia partiremos de nuestro socorrido ejemplo de la clase Alumno.

public class Alumno {
	private String nombre;
    private String apellidos;
    private String dni;
    private Integer edad;
    private String sexo;
	
	private int codAlumno;
	private Lis<Asignatura> asignaturas;
	
	public Alumno (int codAlumno, String nombre, String apellidos, String dni, Integer edad, String sexo, List<Asignatura> lsAsignaturas) {
		this.nombre = nombre;
    	this.apellidos = apellidos;
    	this.dni = dni;
    	this.edad = edad;
    	this.sexo = sexo;
		this.codAlumno = codAlumno;
		this.asignaturas = lsAsignaturas;
	}

        public void setCodAlumno(int codAlumno) {
		this.codAlumno = codAlumno;
	}
	public int getCodAlumno() {
		return codAlumno;
	}
	public void setAsignaturas(List<Asignatura> asignaturas) {
		this.asignaturas = asignaturas;
	}
	public List<Asignatura> getAsignaturas() {
		return asignaturas;
	}
	
	public void asignarAsignatura(Asignatura asignatura) {
		asignaturas.add(asignatura);
	}

	public double getNotaMedia() {
		double resultado = 0;
		for (int i = 0; i < asignaturas.size(); i++) {
			Asignatura asig = asignaturas.get(i);
			resultado += asig.getNota();
		}
		return Math.round((resultado != 0 ? resultado / asignaturas.size(): 0));
	}
}

Imaginemos por otra parte, que tenemos una clase Profesor, definida tal que:

public class Profesor {
	private String nombre;
    private String apellidos;
    private String dni;
    private Integer edad;
    private String sexo;
	
	private int codAlumno;
	
	public Alumno (int codAlumno, String nombre, String apellidos, String dni, Integer edad, String sexo) {
		this.nombre = nombre;
    	this.apellidos = apellidos;
    	this.dni = dni;
    	this.edad = edad;
    	this.sexo = sexo;
	this.codAlumno = codAlumno;
	}

        public void setCodAlumno(int codAlumno) {
		this.codAlumno = codAlumno;
	}
	public int getCodAlumno() {
		return codAlumno;
	}

 public String getNombre() {
        return nombre;
    }
 
    public void setNombre(String nombre) {
        this.nombre = nombre;
    }
 
    public String getApellidos() {
        return apellidos;
    }
 
    public void setApellidos(String apellidos) {
        this.apellidos = apellidos;
    }
 
    public String getDni() {
        return dni;
    }
 
    public void setDni(String dni) {
        this.dni = dni;
    }
 
    public Integer getEdad() {
        return edad;
    }
 
    public void setEdad(Integer edad) {
        this.edad = edad;
    }
 
    public String getSexo() {
        return sexo;
    }
 
    public void setSexo(String sexo) {
        this.sexo = sexo;
    }
 
}

Como se puede ver, las clases Alumno y Profesor comparten mucho código replicado. Los campos nombre, apellidos, DNI, sexo y edad, por tanto, se pueden encapsular en una clase padre, que llamaremos Persona y haremos que ambas clases hereden de ella toda esa funcionalidad común.

public class Persona {
	 
    private String nombre;
    private String apellidos;
    private String dni;
    private Integer edad;
    private String sexo;
    
    Persona() {
    	super();
    }
    
    public Persona(String nombre, String apellidos, String dni, Integer edad, String sexo) {
    	super();
    	this.nombre = nombre;
    	this.apellidos = apellidos;
    	this.dni = dni;
    	this.edad = edad;
    	this.sexo = sexo;
    }
    
    public String getNombre() {
        return nombre;
    }
 
    public void setNombre(String nombre) {
        this.nombre = nombre;
    }
 
    public String getApellidos() {
        return apellidos;
    }
 
    public void setApellidos(String apellidos) {
        this.apellidos = apellidos;
    }
 
    public String getDni() {
        return dni;
    }
 
    public void setDni(String dni) {
        this.dni = dni;
    }
 
    public Integer getEdad() {
        return edad;
    }
 
    public void setEdad(Integer edad) {
        this.edad = edad;
    }
 
    public String getSexo() {
        return sexo;
    }
 
    public void setSexo(String sexo) {
        this.sexo = sexo;
    }

@Override     
public String toString() {
        String nuevalinea = System.getProperty("line.separator");
        String resultado = "DATOS DE LA PERSONA: " + nuevalinea + 
                "Nombre: " + this.getNombre() + nuevalinea + 
                "Apellidos: " + this.getApellidos() + nuevalinea + 
                "DNI: " + this.getDni() + nuevalinea +
                "Edad: " + this.getEdad() + nuevalinea +
                "Sexo: " + this.getSexo() + nuevalinea;
 
        return resultado;
    }
    
	@Override
	public boolean equals(Object object) {
		final Persona aux = (Persona) object;
		if (this == object)
	           return true;
		else if (object == null)
	           return false;
		else if (getClass() != object.getClass())
	           return false;
		else if (this.dni.equals(aux.getDni())) {
			return true;
		} else {
			return false;
		}
	}
}


public class Alumno extends Persona {
	
	private int codAlumno;
	private List<Asignatura> asignaturas;
	
	public Alumno (int codAlumno, String nombre, String apellidos, String dni, Integer edad, String sexo) {
		super(nombre, apellidos, dni, edad, sexo);
		this.codAlumno = codAlumno;
		this.asignaturas = new ArrayList<Asignatura>();
	}
	public void setCodAlumno(int codAlumno) {
		this.codAlumno = codAlumno;
	}
	public int getCodAlumno() {
		return codAlumno;
	}
	public void setAsignaturas(List<Asignatura> asignaturas) {
		this.asignaturas = asignaturas;
	}
	public List<Asignatura> getAsignaturas() {
		return asignaturas;
	}
	
	public void asignarAsignatura(Asignatura asignatura) {
		asignaturas.add(asignatura);
	}

	public double getNotaMedia() {
		double resultado = 0;
		for (int i = 0; i < asignaturas.size(); i++) {
			Asignatura asig = asignaturas.get(i);
			resultado += asig.getNota();
		}
		return (resultado != 0 ? resultado / asignaturas.size(): 0);
	}

@Override 
    public String toString() {
        String nuevalinea = System.getProperty("line.separator");
        String resultado = "DATOS DEL ALUMNO: " + nuevalinea + 
                "Nombre: " + this.getNombre() + nuevalinea + 
                "Apellidos: " + this.getApellidos() + nuevalinea + 
                "DNI: " + this.getDni() + nuevalinea +
                "Edad: " + this.getEdad() + nuevalinea +
                "Sexo: " + this.getSexo() + nuevalinea;
 
        return resultado;
    }
}


public class Profesor extends Persona {
	private int codProfesor;
	
	public Profesor (int codProfesor, String nombre, String apellidos, String dni, Integer edad, String sexo) {
		super(nombre, apellidos, dni, edad, sexo);
		this.codProfesor = codProfesor;
	}
	public void setCodProfesor(int codProfesor) {
		this.codProfesor = codProfesor;
	}

	public int getCodProfesor() {
		return codProfesor;
	}

@Override 
    public String toString() {
        String nuevalinea = System.getProperty("line.separator");
        String resultado = "DATOS DEL PROFESOR: " + nuevalinea + 
                "Nombre: " + this.getNombre() + nuevalinea + 
                "Apellidos: " + this.getApellidos() + nuevalinea + 
                "DNI: " + this.getDni() + nuevalinea +
                "Edad: " + this.getEdad() + nuevalinea +
                "Sexo: " + this.getSexo() + nuevalinea;
 
        return resultado;
}

Por tanto, la clase Persona encapsula toda la funcionalidad común, la cual heredan las clases Profesor y Alumno. Cualquier hijo de la clase Persona, ya sea Profesor o Alumno, podrá invocar a los métodos heredados por su clase padre.

Es importante aclarar, eso sí, que sólo se heredarán aquellos elementos con visibilidad Protected o Public, como vimos en la pildora de visibilidad muy por encima. Por ejemplo, desde la clase Alumno no podemos acceder directamente al DNI con un super.dni, pero sí que podemos hacerlo a través de los métodos setDNI y getDNI, los cuales son públicos.

Hemos creado dos nuevos métodos comunes, equals y toString, que como se puede ver llevan una anotación, @Override. Esto significa que es un método heredado que se va a reescribir para tener una conducta específica y adaptada a la clase hijo. Por ejemplo, los métodos toString de Alumno y Profesor, como se puede ver, devuelven un texto personalizado para esas clase, es decir, sobrescribe el método heredado genérico para cualquier Persona.

Y os preguntareis, ¿y los métodos equals y toString de la clase padre Persona? ¿Por qué tienen también la anotación @Override? Pues porque estos métodos también son heredados. En Java todos los objetos heredan de la clase Object y la clase Object tiene definidos métodos básicos, como toString o equals.

Por último, otra palabra reservada en herencia que utilizaremos mucho es super, la cual tiene una funcionalidad similar a this. Mientras que this, la que ya conocemos, hace mención a la clase en sí, super hacer mención a su clase padre. Por eso, para llamar al constructor de la clase Persona utilizamos la palabra super. De la misma forma, si por ejemplo quisiéramos utilizar el método toString de la clase padre dentro de un método de, por ejemplo, Alumno, utilizaríamos la sentencia super.toString().

Y ya está, no hay más misterio. Como veis, la herencia, aunque potente, es muy sencilla de implementar y entender. En la próxima pildorita veremos la herencia en todo su esplendor con el Polimorfismo y ya con eso, podremos decir que ya sí que sí entendéis la Programación Orientada a Objetos y podéis animaros sin miedo a empezar a programar vuestras propias aplicaciones en Java, C#, o cualquier otro lenguaje POO. No obstante, hay algunas cosas ajenas a la POO pero muy importantes en Java, como las Excepciones, que daremos en otra pildorita extra y con los que no sólo podremos programar en POO, sino tener un buen control de los errores.

Índice de Pildoritas

Share
14
Dec 16

Pildoritas de POO y Java: Relaciones entre Clases

pildoras poo java
En la anterior pildorita os dije que hablaríamos de la Herencia y el Polimorfismo, y aunque esa pildorita está prácticamente terminada en borradores, dándole vueltas a las siguientes pildoritas, me daba cuenta que la que tenía planteada como continuación debía de ir antes, es decir, ésta, sobre relaciones entre clases. Así que nada, esto significa más espera entre la anterior pildorita y ésta, pero el lado bueno es que la siguiente la sacaré en breves.

Llevo unos 7 años trabajando en el desarrollo software y he pasado por multitud de proyectos de gran envergadura. Si algo tengo claro en todos estos años, es que se hace muy mal código - por diversos motivos que no vienen al caso - y que dónde más se falla es, precisamente, en las relaciones de clases: códigos espagueti, pésima modularización y encapsulación... Todos esos problemas vienen, en la mayoría de casos, porque no se tienen del todo claro las relaciones entre clases en la parte más importante del desarrollo, el diseño. Es por eso que antes de entrar en temas de Herencia (algo que muchos desarrollores sí que comprenden bien), creo que es mejor para el aprendizaje de los anteriores conceptos que veamos este tema, que permite asentarlos. Ya habrá tiempo de entrar en la siguiente relación, la generalización, ya que la Herencia no deja de ser también una relación de dos clases.

En la anterior pildorita vimos lo que era un mensaje, y que cuando un objeto lanza un mensaje a otro, estos se comunican y colaboran entre sí. Se dice que existe una Relación entre dos clases si dos objetos de las respectivas clases colaboran entre sí.

Hay tres tipos de relaciones entre clases que a continuación veremos de forma más detallada: Composición, asociación y uso.

Para mayor comprensión de las mismas, utilizaremos el siguiente ejemplo, donde se pueden ver los tres tipos de relaciones:

public class Alumno {
	private String nombre;
    private String apellidos;
    private String dni;
    private Integer edad;
    private String sexo;
	
	private int codAlumno;
	private Lis<Asignatura> asignaturas;
	
	public Alumno (int codAlumno, String nombre, String apellidos, String dni, Integer edad, String sexo, List<Asignatura> lsAsignaturas) {
		this.nombre = nombre;
    	this.apellidos = apellidos;
    	this.dni = dni;
    	this.edad = edad;
    	this.sexo = sexo;
		this.codAlumno = codAlumno;
		this.asignaturas = lsAsignaturas;
	}

        public void setCodAlumno(int codAlumno) {
		this.codAlumno = codAlumno;
	}
	public int getCodAlumno() {
		return codAlumno;
	}
	public void setAsignaturas(List<Asignatura> asignaturas) {
		this.asignaturas = asignaturas;
	}
	public List<Asignatura> getAsignaturas() {
		return asignaturas;
	}
	
	public void asignarAsignatura(Asignatura asignatura) {
		asignaturas.add(asignatura);
	}

	public double getNotaMedia() {
		double resultado = 0;
		for (int i = 0; i < asignaturas.size(); i++) {
			Asignatura asig = asignaturas.get(i);
			resultado += asig.getNota();
		}
		return Math.round((resultado != 0 ? resultado / asignaturas.size(): 0));
	}
}

 

Composición

Es la relación que se constituye entre el todo y la parte. En otras palabras, existe una relación de composición entre la clase A y la clase B, cuando la clase A "tiene un" objeto de la clase B.

Esta colaboración se traduce en la delegación de la clase todo a las partes de ciertas acciones determinadas para implementar la funcionalidad global.

Con esta colaboración se respetará el principio de encapsulación y modularidad por parte de las clases que componen a la clase A.

A la hora de plasmar en código esta relación con los conceptos que hemos visto en las anteriores pildoritas, esto se traduce en un atributo de la clase B en la clase A. Por tanto, tendrá una visibilidad privada y no es versátil, es decir, no puede ser intercambiable por otros objetos. Así mismo, tendrá una duración en la colaboración no momentánea en el tiempo.

Es el caso del atributo codAlumno de nuestra Clase de ejemplo Alumno. Si hiciéramos una clase Profesor, no tendría sentido introducir un código de alumno, por tanto, no es una entidad versátil. Así mismo, el código de alumno se utilizará en muchas funcionalidades de la clase Alumno, ya que es un identificador único similar al DNI. Así mismo ocurre con el resto de atributos que identifican inequívocamente a un Alumno, como nombre, apellidos, DNI...todos aquellos datos que se inicializan a la hora de construir el objeto y que existirán durante todo el ciclo de vida del objeto Alumno.

 

Uso

Es la relación que se establece de forma momentánea entre un objeto cliente (pide algo) y un objeto servidor (suministra ese algo). Por tanto, el objeto de la clase A enviará un mensaje a un objeto de la clase B en un momento dado sin dependencias futuras. Así mismo, el uso de la clase B no dependerá únicamente de la clase A, sino que podrá ser utilizada por otras muchas clases.

Esto significa que la clase A, la cliente, tendrá como parámetro o valor devuelto de un método un objeto de la clase servidora B si esa colaboración es pública, y como un objeto local dentro de un método si es una colaboración privada. La versatilidad de ser intercambiada la clase B por otra, es, por tanto, elevada.

Por ejemplo, el método getNotaMedia() de la clase Alumno, redondea el resultado final utilizando la clase Math e invocando a su método round. Esta clase no es necesaria obviamente para ese cálculo. Podríamos decidir no redondear, o redondear nosotros creando un método propio que realice esta funcionalidad.
 

Aociación

La asociación es una relación de uso donde la relación entre la clase A y la clase B sí que perdura en el tiempo, es decir, se realiza en diversos momentos del ciclo de vida del objeto A, por lo que se crea una relación de dependencia entre ambos objetos. Al igual que la relación de uso, la responsabilidad de manejar ese objeto B no dependerá únicamente del objeto A, sino que podrá ser utilizado por más objetos de diferentes clases.

La asociación, al ser una relación pública generalmente y de una temporalidad no momentánea, pero teniendo una versatilidad reducida, se traducirá en un atributo en la clase A cliente que apuntará a la clase B servidora.

Un ejemplo de este tipo de relación sería la existente entre el Alumno y las Asignaturas. La clase Asignatura es independiente del Alumno, ya que puede existir sin necesidad de que haya Alumnos matriculados a ella. Así mismo, el Alumno puede estar dado de alta en la universidad sin estar matriculado en ninguna asignatura.
 
Espero que esta pildorita haya sido clara y de verdad afiance conceptos fundamentales ya no en el desarrollo de buenos programas en POO, sino de códigos de calidad bien estructurados y fácilmente mantenibles. Cuando vi este capítulo de la asignatura de Programación II me resultó lioso y no le presté toda la atención que merecía. Me centraba en saber sacar las clases de un problema, definir que atributos tenía, y los métodos y sus funcionalidades. Vaya, estaba anclada en lo que conocía, la imperativa. No fue hasta ya después en Ingeniería del Software que llegué a entender del todo para que servía esto y que, la Programación Orientada a Objetos sin estas relaciones no deja de ser modulada, fallo que luego he visto años más tardo muy extendido en la profesión. Sin entender las relaciones, no se sabe de verdar trabajar con POO y poder de verdad explotar la modularidad y ecapsulación que ofrece.

La siguiente pildorita, sí que sí, será la de Herencia y Polimorfismo, la cual, como comenté antes, está ya acabada, así que en una semana tendréis una nueva dosis javera con la que ya prácticamente habremos acabado esta serie 🙂

Índice de Pildoritas

Share
8
Sep 16

Pildoritas de POO y Java: Atributos y Métodos

pildoras poo java
En la anterior pildorita de POO y Java introducimos el concepto de Visibilidad de una clase, la cual nos da la tan ansiada encapsulación.

No obstante, aunque ya llevamos dos pildoritas viendo atributos y métodos, todavía no hemos ahondado suficiente en ciertos conceptos a tener en cuenta a la hora de utilizarlos, pero que ahora que tenemos claro el concepto de Ámbito, podemos afrontar.

Atributos

Los atributos son las variables y constantes que definen los estados o datos de un objeto. Vimos en la anterior pildorita que, al igual que con el resto de elementos existentes en una clase, los atributos también se ven afectados por los modificadores de visibilidad. No obstante, estos modificadores de visibilidad (public, private, static o final), pueden venir seguidos de los modificadores de las características del atributo (su vida útil, sus posibles cualidades y valores, etc.).

  • static: El modificador static, que vimos en la anterior pildorita, se trata como un modificador de característica, y como vimos ya, especifica que el atributo pertenece a la clase y no a los objetos creados a partir de ella.
  • final: El atributo es una constante, por lo que deberá de tener obligatoriamente un valor inicial. Se suele especificar su nombre en mayúsculas por convención.
  • trascient: El atributo no es serializable, es decir, no puede ser convertido en una cadena de bytes que resulte fácilmente manipulable por red, almacenamiento en ficheros, bases de datos, etc. Utilizando este modificador evitamos que este atributo y su valor se tengan en cuenta a la hora de serializar el objeto que los contiene.
  • volatile: Este modificador indica a Java que este atributo puede ser accedido de forma concurrente por varios hilos de forma simultánea.

Métodos

Los métodos son un conjunto de instrucciones definidas dentro de una clase, que realizan tareas y, por norma general, operan sobre los estados de los atributos de dicha clase.

Así mismo, los métodos son el mecanismo que implementa la comunicación entre objetos, lo que comúnmente se llama Paso de Mensajes.

Un objeto, el emisor, solicita ejecutar uno de sus métodos a otro objeto, con el objetivo de que este realice alguna acción, o devuelva cierta información.

Los métodos así mismo, siguen la misma estructura que las funciones y procedimientos de la programación estructurada y pueden recibir, o no, parámetros, así como devolver, o no, valores.

[modificadores] tipo nombreMetodo ([lista parametros]) {
     // instrucciones
     [return valor;]
}

Los modificadores, que no son obligatorios (los corchetes significan que puede estar, o no), indicarán el ámbito de uso del método, y son los que ya hemos visto en la pildorita de Visibilidad y Ámbito.

Constructores

El constructor es un método especial de la clase que se ejecuta siempre que se crea un objeto de dicha clase. Sirve para inicializar los estados del objeto y que sus atributos siempre contengan valores válidos.

Una clase puede tener uno o más constructores. Así mismo, si no se define un constructor, el compilador crea automáticamente el constructor por defecto, un constructor sin parámetros que no hace nada y en el que los atributos del objeto se inicializan a los predeterminados por el sistema.

Para que un método sea interpretado como constructor de una clase debe tener las siguientes características:

  • Tiene el mismo nombre que la clase que contiene
  • No puede devolver ningún valor, ni siquiera el valor void
  • Es público, para que pueda invocarse desde cualquier parte donde se quiera crear un objeto de dicha clase
  • No se hereda

Por ejemplo, volviendo al ejemplo de Persona, cuando creábamos un objeto de este tipo en la clase PruebaPersona, lo hacíamos a través de la sentencia, Persona mar = new Persona();, dicha sentencia llama al constructor por defecto, public Persona();

Si quisiéramos, podríamos crear un nuevo constructor que inicialice los atributos a los valores pasados por parámetro, y así nos ahorraríamos las sentencias de set como mar.setNombre("Mar"), en la que dábamos valor a dicho atributo.

public class Persona {
	 
    private String nombre;
    private String apellidos;
    private String dni;
    private Integer edad;
    private String sexo;
    
    public Persona(String nombre, String apellidos, String dni, Integer edad, String sexo) {
    	super(); // Se llama al constructor por defecto de la clase superior, Object, ya que no se hereda. No es necesario en este caso, pero por convención se pone siempre
    	this.nombre = nombre;
    	this.apellidos = apellidos;
    	this.dni = dni;
    	this.edad = edad;
    	this.sexo = sexo;
    }

Ahora bien, al definir nosotros un constructor, el compilador dejará de crear el constructor por defecto, por lo que, en caso de querer un constructor sin parámetros, deberemos definirlo nosotros también. ¿Y como hacemos esto? Gracias a la Sobrecarga de métodos.

Sobrecarga de métodos

La sobrecarga de métodos es la creación de varios métodos con el nombre, pero con firmas diferentes.

La firma de un método se compone del nombre, la lista de argumentos y el dato devuelto. No obstante en Java, esto último no se tiene en cuenta, por lo que la firma es la combinación del nombre, y el número y tipo de argumentos.

Por ejemplo, los dos constructores de nuestro anterior ejemplo, tienen firmas diferentes por lo que el intérprete es capaz de diferenciarlos aunque tengan el mismo nombre.

public Persona(String nombre, String apellidos, String dni, Integer edad, String sexo) {
	this.nombre = nombre;
    	this.apellidos = apellidos;
    	this.dni = dni;
    	this.edad = edad;
    	this.sexo = sexo;
}

public Persona() {
	super();
}
 

La sobrecarga de métodos da pie a un concepto mucho más amplio conocido como Polimorfismo, pero esto ya es temática para la próxima pildorita, en la cual veremos también otro concepto fundamental de la Programación Orientada a Objetos: la Herencia.

Índice de Pildoritas

Share
24
May 16

Pildoritas de POO y Java: Visibilidad y ámbito

pildoras poo java

En la anterior píldora de POO y Java vimos que en la Programación Orientada a Objetos definimos clases, las cuales una vez se instancian son objetos concretos de esa entidad, con su propio estado.

Así mismo, sabemos que las clases y objetos se componen de atributos y métodos, es decir, estados y acciones sobre esos estados. Vimos la manera de definir variables (atributos) y funciones (métodos) en los primeros capítulos de Imperativa, no obstante, en POO hay que tener en cuenta nuevos conceptos propios del paradigma. El fundamental es la Visibilidad, la cual nos da la tan ansiada encapsulación. También debemos conocer cierto concepto previo utilizado en Java y que afecta a la definición de lo qué es visibilidad: Los paquetes.

Para mayor claridad de los conceptos, utilizaremos variaciones en el ejemplo inicial de la anterior pildorita, por lo que es recomendable tenerla abierta en otra pestaña.
 

Paquetes

Los paquetes no son más, siendo muy burdos, que carpetas, y sirven para organizar nuestras clases y darles un nombre único. Los paquetes además, como ocurre con las carpetas, se organizan en una estructura de árbol. Cuando creamos un paquete, se crea una estructura de directorios asociados.

En la anterior pildorita se definió una clase y aunque no se llegó a explicar, la primera línea con la palabra package, indica el paquete donde se encuentra alojada.

// Directorio donde se encuentra la clase Persona y PruebaPersona: 
// ejemplo1/persona
package ejemplo1.persona

carpetas
Así mismo, cuando utilicemos una clase del mismo paquete en otra clase, no tendremos que especificar su ruta. Si no es el caso, utilizaremos la palabra import seguida del paquete y clase.

import ejemplo1.persona.Persona

 

Visibilidad y acceso

La visibilidad, o vista, nos indica por quién es accesible un determinado elemento y es aplicable tanto a clases, como a atributos y métodos. Para diferenciar la visibilidad de un elemento, se utilizan los modificadores de acceso, palabras reservadas que especifican el tipo de visibilidad de dicho atributo, método, etc.

Hay cuatro tipos de modificadores: public, private, protected, default y static.

public

La vista public permite acceder al elemento desde cualquier clase del espacio de trabajo. Un ejemplo de esta vista es la de todos los métodos de la clase Persona o la de su atributo codigoUnico. Como vimos, desde PruebaPersona se accede a él sin necesidad de métodos intermedios.

package ejemplo1.persona;

public class Persona {
 
    public String codigoUnico; 
    
    public String toString() {
        String nuevalinea = System.getProperty("line.separator");
        String resultado = "DATOS DE LA PERSONA: " + nuevalinea + 
                "Codigo Unico: " + this.codigoUnico + nuevalinea +
                "Nombre: " + this.getNombre() + nuevalinea + 
                "Apellidos: " + this.getApellidos() + nuevalinea + 
                "DNI: " + this.getDni() + nuevalinea +
                "Edad: " + this.getEdad() + nuevalinea +
                "Sexo: " + this.getSexo() + nuevalinea;
 
        return resultado;
    }
}

package ejemplo1.persona

public class PruebaPersona {
 
    public static void main(String[] args) {
         
        Persona mar = new Persona();        
        mar.codigoUnico = "112";
        System.out.println(mar.toString());
         
    }
}

private

La vista private, por el contrario, sólo permite que el elemento sea utilizado por otros objetos de la misma clase, pero no por elementos de clases diferentes. Como se ve en el ejemplo anterior, el método toString() utiliza los atributos privados sin necesidad de utilizar métodos públicos que devuelvan sus valores. Sin embargo, para poder utilizarse desde la clase PruebaPersona es necesario hacerlo a través de sus métodos set y get.

package ejemplo1.persona;

public class Persona {
	
	private String nombre;
	
	 public String getNombre() {
        return nombre;
    }
 
    public void setNombre(String nombre) {
        this.nombre = nombre;
    }
}

package ejemplo1.persona

public class PruebaPersona {
 
    public static void main(String[] args) {
         
        Persona mar = new Persona();        
        mar.setNombre("Mar");
        System.out.println("El nombre de la persona es: " + mar.getNombre());
         
    }
}

¿Y que pasaría si intentaramos acceder a un atributo privado? Por ejemplo, el DNI:
private-example
Como se puede ver, se muestra un error pre-compilación, y se nos sugiere o bien cambiar la visibilidad del atributo - a public, por ejemplo - o utilizar un método set, como se hace en la línea anterior.

protected

La vista protected indica que un elemento es accesible desde una clase del mismo paquete, o por una clase que herede de la clase en la que este elemento se encuentra, sin importar el paquete. Una vez más, dejaremos aparcada la herencia, la cual requiere una pildorita por si sola. Cuando toque explicaremos más en profundidad este aspecto.

default

La vista default, que se puede también indicar sin poner ningún modificador de acceso delante del elemento, permite al elemento ser utilizado desde cualquier clase del mismo paquete.

public class Persona {
 
    String codigoUnico; 

}

package ejemplo1.persona

public class PruebaPersona {
 
    public static void main(String[] args) {
         
        Persona mar = new Persona();        
        mar.codigoUnico = "112";
        System.out.println("El Codigo de Persona es: " + mar.codigoUnico);
         
    }
}

static

Por último, existe el modificador static, el cual indica que el elemento pertenece a la clase y no a las instancias de la misma (objetos). Por ejemplo, como vimos en el ejemplo de la anterior pildorita, el main se declara como static. Esto permite acceder al método main sin necesidad de instanciar la clase que lo contiene.

package ejemplo1.persona;
/**
 * Clase Persona
 * @version 1.0
 * @since 2014
 */
public class Persona {
 
    static int numPersonas = 0;
    private String nombre;
   
   // Esto es un constructor 
   Persona() {
	   numPersonas++;
   }

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

package ejemplo1.persona;
/**
 * Clase Test para probar la clase Persona
 * @version 1.0
 * @since 2014
 */
public class PruebaPersona {
 
    public static void main(String[] args) {
         
        Persona objeto1 = new Persona();
        objeto1.setNombre("Mar");
        
        Persona objeto2 = new Persona();
        objeto2.setNombre("Pepe");
        
        System.out.println("El nombre del objeto 1 es: " + objeto1.getNombre());
        System.out.println("El nombre del objeto 2 es: " + objeto2.getNombre());
        System.out.println("Se han creado " + Persona.numPersonas + " personas");
    }
}

El resultado que tendremos es el siguiente:

El nombre del objeto 1 es: Mar
El nombre del objeto 2 es: Pepe
Se han creado 2 personas

Existen otros modificadores de acceso como native, utilizado para indicar código diferente a Java, trascient, que se utiliza para indicar que este elemento no es persistente, final, para especificar que una variable determinada tendrá un valor fijo, volatile y synchronized, utilizados para la programación concurrente y abstract, para herencia. Al no ser modificadores de acceso alejados del concepto de visibilidad, no entran en esta pildorita, pero ya habrá tiempo de verlos.

Índice de Pildoritas

Share
5
Apr 16

Pildoritas POO y Java: El que mucho abarca... u_U!

pildoras poo java

Ayer entré en este blog y miré la parte de estadísticas de la web, cosa que no miraba desde hacía decenios.

Pese a que el rumbo de este sitio ha virado enormemente a la política, por lo que pude ver la mayoría de mis visitas – cosa que por otra parte me dio una muy buena alegría – llegan a este blog gracias a mis Pildoritas de Bases de Datos y Programación orientada a objetos en Java.

Estuve revisando las pildoritas y bueno, con las de POO se me cayó la cara de vergüenza, literalmente. Subí el último post, la introducción de POO, en noviembre de 2014, que se dice pronto. Desde entonces todo aquel que entra a esta serie de pildoras se encuentra con la “grata” sorpresa de que falta justamente la parte de POO, ¡en unas pildoritas que supuestamente son de POO!

Así que nada, ayer volví a releer las pildoritas, consulté apuntes y recoloqué ideas en mi cabeza, con la clara resolución de terminar los, como mucho, 3 o 4 posts que pueden faltar para concluírlas.

Para este finde espero tener el siguiente post, centrado en los ámbitos de las clases y objetos.

Como ya va siendo tradición en mis posts, una vez más pido disculpas a todas aquellas personas que puedan haberlas leído y se hayan quedado con la frustración de no verlas acabadas.

Share
2
Jul 15

Google Fotos y el racismo: Crónica de un error anunciado

Ayer salió a la palestra una noticia de actualidad sobre Google Fotos y el hecho de que ésta aplicación etiquetara como "gorilas" a algunas personas negras. Durante estos días han corrido ríos de tinta en la red sobre el supuesto racismo de Google a la hora de hacer sus aplicaciones, pero hay que tener en consideración algunos temas sobre IA para entender el error, que nada tiene que ver con el racismo.

Lo primero y fundamental es aclarar a la gente que la IA tiene poco de inteligente y mucho de artificial. Si algo enseña este campo es que los seres vivos somos máquinas increibles, capaces de realizar cálculos a velocidades vertiginosas y sin casi errores, algo que una máquina es incapaz hoy por hoy. Para que esto sea posible, muy probablemente tendremos que esperar a que otros campos como la neurociencia nos alumbren sobre como funciona nuestra "CPU biológica", el cerebro.

Por otra parte, la IA es un campo que aunque se lleva investigando desde los 60 sigue en pañales, ya que hasta hace menos de una década siquiera teníamos equipos para ejecutar estos algoritmos en unos tiempos aceptables (cuando digo aceptables, me refiero a bajar de las horas y semanas incluso que podían tardar ciertos procesamientos). Aún hoy muchos algoritmos siguen sin poderse ejecutar en tiempos asumibles. Por tanto, la IA es un campo aún en investigación y aunque las empresas intenten sacar productos comercializables, hay que tener en cuenta que no tendremos tasas de acierto del 100%, es más, es algo que dificilmente podremos tener a corto y medio plazo.

googlevil

El error racial de Google Fotos no es el único, además. Hace unos meses Flickr tuvo el mismo problema: etiquetar a un negro como un mono. ¿Por qué ocurre esto? Empecemos por el principio.

¿Qué es un clasificador?

Un clasificador es un algoritmo que, dado un dato de entrada, nos devuelve como salida una etiqueta o clase de pertenencia. Para que este algoritmo asigne una etiqueta a un determinado dato, necesita de un entrenamiento previo con unos datos suficientemente robustos para ser capaz de identificar esa clase en todos los casos (datos ya etiquetados). Por ejemplo, para un ordenador una cara de frente y otra de perfil, o una cara de una persona blanca o asiática, con una negra, nada tienen que ver. Igual ocurre con cosas tan nímias como la iluminación: no es igual una cara iluminada con el sol de mediodía, que una cara iluminada con fluorescentes. ¿Por qué? Porque para el ordenador esa foto a clasificar no es más que una matriz numérica, en donde cada campo indica la intensidad de un píxel, nada más. El no sabe de temas raciales y culturales.

La elección de los datos de entrenamiento sigue siendo una temática ampliamente investigada en el campo, ya que por norma general no se puede contar con muchos datos que tengan las variaciones suficientes para que un clasificador tenga tasas de acierto perfectas, ni tampocos somos capaces de encontrar descriptores (vectores numéricos que representan cierta característica discriminante del dato, los bordes de una imagen, por ejemplo) robustos para que los clasificadores sean tan óptimos como el cerebro humano.

Por tanto, ¿qué ha pasado con Google Fotos? Sinceramente no tengo ni idea como será el clasificador de Google internamente (ojalá :P), pero sí se que es una red neuronal convolucional, por lo que me puedo imaginar a grandes rasgos los problemas que han causado que una máquina sin ética ni moral pueda ser "racista".

Para empezar, imagino que uno de sus descriptores pueda ser el color, más que nada porque el color es algo casi inherente a la visión artificial. Aunque Google use fotos de todo tipo de razas, hay que de nuevo recordar que el ordenador lo único que ve son celdas (píxeles) con valores numéricos del 0 al 255. Los asiáticos y blancos tendremos umbrales de color similares, mientras que las personas negras no están comprendidas dentro de estos umbrales. Por tanto, habrá muchos más ejemplos de caras que tengan umbrales similares (asiáticas, europeas, etc.) y otro grupo que no, por lo que si no se asigna un peso pequeño a este descriptor, el algoritmo lo utilizará como indicativo de una cara humana, rechazando a una gran parte de la población por motivos de color. Es un tema de proporción de imágenes colgadas en Google, quién tiene más población con acceso a internet, etc. Nos guste o no, por desgracia la mayoría de población negra no tiene acceso a un ordenador, al menos no en la misma proporción que europeos y asiáticos. No obstante, estoy segura que aquí Google ha sabido muy bien compensar los datos y pesos para que el color no fuera muy discriminante.

Por otra parte, se habrán tenido en cuentas descriptores de forma, ya sean con bordes, esquinas, etc. Nos guste o no, los seres humanos somos una especie de primate, por lo que nuestros rasgos son muy similares a los de nuestros parientes los monos. Por su parte, como sabéis, los gorilas son de un predominante color negro.

Los clasificadores están basados en probabilidades. Este mira la probabilidad / peso de un dato para cada etiqueta, y se queda con el valor más alto. Por tanto, ¿es raro que en determinadas circunstancias de gestos, iluminación, etc. el clasificador "monos" de valores más altos que el de "humanos"? Por supuesto que no. Como ya contestó Yonatan Zunger, arquitecto jefe de Google+, también tienen problemas con caras blancas, que son etiquetadas a veces como perros y focas. Si el algoritmo es tan "tonto" de confundirnos con una foca, ¿cómo no va a fallar con un primate?

Por tanto, el problema en el algoritmo de reconocimiento facial de Google no es que no se tuvieran en cuenta todas las razas y sexos posibles, sino el hecho de sacar un producto al público de un campo que sigue hoy en día en desarrollo, y del que no podemos asegurar tasas de acierto perfectas. Como afirmaba antes, el ordenador no sabe de temas éticos y culturales, por lo que igual que puede fallar etiquetando blancos como focas sin que nadie se sienta insultado, puede también dar resultados que sí afecten a cierto colectivo, como el caso de los primates, sin que nosotros podamos saberlo a priori.

La pregunta por tanto es, ¿debemos limitar la investigación de estos productos al campo académico porque a veces puedan fallar y darnos resultados incorrectos?

Artículo publicado en El Boletin:

Google Fotos y el racismo: crónica de un error anunciado

Share
11
Dec 14

Google y la libertad de prensa abandonan España

Si algo le ha gustado siempre a este gobierno es tener medios de comunicación dignos de países bananeros, esos a los que estos días en la cumbre iberoamericana Rajoy da lecciones de democracia.

Lo que le gusta al PP son portadas como las que acompañan este artículo, o piezas en los informativos como la de este lunes de Telemadrid, que podéis admirar justo debajo.

telamdrid

En este tema tampoco se escapan el PSOE o CIU, pero en el caso del PP siempre ha sido una prioridad, hasta el punto de "robar" los medios que el PSOE tenía comprados, como por ejemplo El País, medio que últimamente tiene una línea editorial digna del ABC.

La forma más directa de manipulación ha sido siempre la utilización de los medios de comunicación públicos que pagamos todos. Un ejemplo claro es Telemadrid, que aparte de haberla expoliado a base de puestos a amigotes y desorbitadas y oscuras concesiones como las que se dieron a su amigo Cerezo, tiene una línea editorial cercana a Fuerza Nueva. Poco importa si tienen unas cifras en share del 5% (la que llegó a ser la cadena más vista de Madrid), lo importante es silenciar la realidad y engañar a la ciudadanía.

razon Una de las primeras medidas del gobierno al llegar a la ejecutiva central fue precisamente exportar el modelo de Telemadrid a TVE, la que hasta ese momento había recibido premios a nivel internacional por sus informativos, o por programas como Informe Semanal, y que actualmente es una de las cadenas menos vistas con un triste 10% de share. Esa gran tarea la llevó a cabo primeramente Somoano (el que fue presentador de informativos de Telemadrid), al cual sustituyeron al día siguiente de poner la primera pieza de Podemos tras meses de silencio. Actualmente esta tarea la perpetúa José Antonio Álvarez Gundín, el cual ya ni disimula y ostenta su cargo mientras lo compatibiliza con el de subdirector de La Razón.

La otra manera de comprar a los medios, en este caso los privados, pasa también por la mamandurria y el expolio público, en esta ocasión a través de campañas publicitarias tanto electorales como, lo que es peor, estatales, que venden al mejor vocero.

Las concesiones de TDT también han supuesto otra forma más de controlar los medios privados. En Madrid, por ejemplo, el PP se dedicó a repartir todas las franjas disponibles entre medios de ultra derecha: Intereconomía o 13TV son ejemplos obvios.

La gente, harta de que las traten como idiotas, castiga estos medios con shares irrisorios y acude al único lugar libre que nos queda: Internet. Pero el gobierno, como ya hizo en su momento el PSOE con el Canon de la SGAE, ha corrido raudo a limitar éste ágora virtual.

El Canon AEDE, que se aprobará este lunes en el congreso, no es más que la enésima mamandurria para premiar a los voceros del régimen y acabar con la libertad de prensa en la Red. Esta medida obligará a que todos los enlazadores paguen un impuesto revolucionario por dar visitas a estos panfletos, ya sean medios inscritos al CEDRO (algo así como la SGAE de los editores), como a aquellos que no, los cuales no verán un céntimo de dichas recaudaciones. De nada servirá que yo cuelgue mis artículos con licencia Creative Commons y los ceda al mundo. En el mundo del neoliberalismo ser solidario está prohibido.

Con motivo de esta ley, Google News ha anunciado hoy mismo que abandona España, algo que muchos ya dábamos por hecho (no es el primer país donde lo hacen), pero que parece que hoy sorprende a muchos internautas.

Algunos esperaban que la empresa del "Don't be evil", aprovechando su posición de fuerza, saldría cual paladín a defender el derecho de libertad de prensa de los españoles. A Google le importa un pimiento la gente y mucho menos España, país sin el que pueden sobrevivir tranquilamente. Prueba clara es que anualmente tributa poco más de un millón de euros y roba la riqueza que genera en España llevándose sus ganancias a paraísos fiscales como las Islas Bermudas.

abc

Muchos internautas afirman que los medios de comunicación españoles, que viven prácticamente en su totalidad de las visitas que les dan estos agregadores, han hecho un Froilán en toda regla. Nada más lejos de la realidad.

El modelo que se instaura es el rescate encubierto de los voceros del régimen. A partir de ahora somos los españoles los encargados de mantener a la fuerza a estos medios. Ya poco importarán los lectores y sus ventas, porque tendrán una entrada fija bien abultada en su balance de cuentas que las hará seguir adelante, sean empresas competentes o empresas copadas por auténticos inútiles, poco importa.

Lo que si creo que sucederá es que una vez más los internautas buscaran vías para poder seguir leyendo prensa libre. Por ejemplo, una medida que tened por seguro sucederá el próximo lunes es que enlazadores como Meneame se irán con sus servidores a otro país y se librarán así, de forma transparente para el usuario, del canon AEDE. La desgracia es que estos agregadores, que también son empresas que crean puestos de trabajo y tributan en el país, se irán a generar riqueza a otros países.

Una vez más, los que pagamos la factura somos los ciudadanos.

Artículo publicado en El Boletin:

Google y la libertad de prensa abandonan España (El Boletin)

Share
21
Nov 14

Pildoritas de POO y Java: Introducción a la Orientación a Objetos

pildoras poo java

Como veíamos en la pildorita introductoria, la evolución de los lenguajes de la programación siempre ha seguido una meta clara: encontrar la metodología más intuitiva para los seres humanos. Para ello, la programación siempre intenta alcanzar el mayor grado de abstracción, modularidad y encapsulación. La Programación Orientada a Objetos no es más que el enésimo y último (o penúltimo si contemplamos la programación orientada a aspectos) intento de alcanzar esas metas, utilizando para ello dos conceptos muy claros: Clases y Objetos.

El mundo real está repleto de Objetos. Algunos son tangibles, como una persona, una mesa o un coche y otros intangibles, como un crédito, una raíz cuadrada o la ventana de una aplicación. Los seres humanos somos criaturas muy observadoras que tendemos además a clasificar esos objetos en diferentes tipos (o Clases) por medio del proceso de abstracción, por el cual se identifican las características esenciales comunes de un conjunto de objetos, prescindiendo de los detalles superfluos.

Por ejemplo, por medio de la observación de otros animales y nosotros mismos, hemos identificado que un conjunto de los mismos somos vertebrados, de sangre caliente, tenemos glándulas mamarias y somos vivíparos (con la excepción del ornitorrinco xD) y los hemos clasificado como Mamíferos.

Un capítulo de biología sobre los Mamíferos nos explica las partes que lo componen, las funciones que realizan, etc., eso es una Clase. Por otra parte tú, o mis gatetes, son objetos de esta clase. Los objetos son entidades concretas que siguen la descripción de dicha Clase.

mamiferosObjetos de la clase Mamífero

En el desarrollo POO se definirá antes de nada la clase y una vez hecho esto, crearemos objetos de esa clase y trabajaremos con ellos. Poniéndonos filosóficos y egocéntricos, los programadores de POO son algo así como Demiurgos, encargados de describir ideas que sirven de molde para los objetos que luego compondrán el mundo real.

Por otra parte, como la POO es imperativa al fin y al cabo, todo se entiende a partir de variables que cambian sus estados durante el transcurso de la ejecución. Para ello, los objetos se compone de atributos, variables que almacenan diferentes estados, y métodos, funciones que realizan diferentes acciones sobre los estados de los atributos.

Hay que tener en cuenta que los atributos también serán objetos (los tipos primitivos no dejan de ser clases también) que componen ese supra-clase. La interacción de estos diferentes objetos entre sí, a partir de lo que se llama mensajes, y las relaciones que existen entre ellos, son precisamente las causantes de que esta programación imperativa marque la diferencia.

Por otra parte, las clases también tienen un ámbito privado y otro público, para conseguir las tan preciadas metas de la encapsulación y abstracción. Tanto las clases, como variables, constantes o métodos, pueden tener un ámbito privado o público, dependiendo si interactuarán con otras clases o son sólo de carácter interno. En el caso de Java también existe otro ámbito, el protected, pero por ahora no vamos a entrar en él.

Veamos ahora un ejemplo muy sencillo de definición de una clase y uso de la misma, para que podáis asimilar las ideas expuestas hasta ahora.

Aunque es un ejemplo muy básico pondré un Diagrama de Clases para que se vea mejor. El UML es un lenguaje de diseño que en sí mismo daría para una serie de Pildoritas nuevas (que espero algún día hacer xD). Cada símbolo tiene significados muy concretos y diferencias con otros que, aunque visualmente no sean muy notables, suelen ser muy importantes a la hora de plasmar nuestro código. También es cierto que se puede llegar a entender en líneas generales el problema sin tener ni idea de UML, que es lo que pretendo en este caso 🙂

f3aec65a

Vamos a definir una clase Persona. Los atributos están al comienzo de la "tabla" Persona y separados por una línea, los métodos. Los símbolos + y - indican su ámbito (público o privado). Por último, tendremos una clase PruebaPersona que simplemente tiene un método main y utiliza una clase Persona.

Para el desarrollo del diagrama, por cierto, he utilizado una herramienta online que no conocía pero me ha enamorado, yuml.me. Genera vía online diagramas de clases, casos de uso y diagramas de actividad. Simplemente hay que definir el diagrama con una sintáxis que se explica muy bien en los ejemplos y te genera directamente una URL de edición, imágenes png, jpg, archivos pdf y json...Vamos, una pasada. Os lo recomiendo.

 package ejemplo1.persona;
/**
 * Clase Persona
 * @version 1.0
 * @since 2014
 */
public class Persona {

	private String nombre;
	private String apellidos;
	private String dni;
	private Integer edad;
	private String sexo;
	
	public String codigoUnico;

	public String getNombre() {
		return nombre;
	}

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

	public String getApellidos() {
		return apellidos;
	}

	public void setApellidos(String apellidos) {
		this.apellidos = apellidos;
	}

	public String getDni() {
		return dni;
	}

	public void setDni(String dni) {
		this.dni = dni;
	}

	public Integer getEdad() {
		return edad;
	}

	public void setEdad(Integer edad) {
		this.edad = edad;
	}

	public String getSexo() {
		return sexo;
	}

	public void setSexo(String sexo) {
		this.sexo = sexo;
	}
	
	public String toString() {
		String nuevalinea = System.getProperty("line.separator");
		String resultado = "DATOS DE LA PERSONA: " + nuevalinea + 
				"Codigo Unico: " + this.codigoUnico + nuevalinea +
				"Nombre: " + this.getNombre() + nuevalinea + 
				"Apellidos: " + this.getApellidos() + nuevalinea + 
				"DNI: " + this.getDni() + nuevalinea +
				"Edad: " + this.getEdad() + nuevalinea +
				"Sexo: " + this.getSexo() + nuevalinea;

		return resultado;
	}
}

Como veis, la clase persona está compuesta por los atributos que le describen, en este caso nombre, apellidos, dni, edad, sexo y codigoUnico. Además, se han creado una serie de métodos para poder obtener los valores de los atributos privados (métodos get) y cambiarlos (métodos set), así como un método toString que devuelve es una representación en formato String de la clase.

Todos los atributos menos codigoUnico son privados, por lo que no se puede acceder directamente desde otra clase a los mismos si no es a través de los métodos públicos get y set creados para este fin. Por su parte el atributo codigoUnico se puede modificar y obtener directamente desde otras clases, como se puede ver en la clase de Prueba de a continuación, ya que está en la vista pública de la clase.

La palabra reservada this, por su parte, lo que hace es indicar que se hace referencia a atributos o métodos del objeto. Existen otras palabras reservas como super, que ya veremos más adelante para que sirven.

package ejemplo1.persona
/**
 * Clase Test para probar la clase Persona
 * @version 1.0
 * @since 2014
 */
public class PruebaPersona {

	public static void main(String[] args) {
		
		Persona mar = new Persona();
		
		mar.codigoUnico = "112";
		
		mar.setNombre("Mar");
		mar.setApellidos("Millan");
		mar.setEdad(27);
		mar.setSexo("F");
		mar.setDni("01168899Q");
		
		
		System.out.println(mar.toString());
		
	}
}

SALIDA DE LA CLASE PruebaPersona:

DATOS DE LA PERSONA:
 Codigo Unico: 112
 Nombre: Mar
 Apellidos: Millan
 DNI: 01168899Q
 Edad: 27
 Sexo: F

Como podéis ver para crear un objeto se utiliza la siguiente sentencia: Persona mar = new Persona(). Esto se llama constructor y lo que hace es crear en memoria una instancia, es decir, un objeto, del tipo Persona. No entraremos en que es un constructor y lo veremos en la siguiente pildorita, pero por ahora basta saber que todas las clases tienen uno sin parámetros, como el utilizado en este ejemplo, encargados de crear objetos concretos en memoría de la clase a la que pertenecen.

El atributo codigoUnico le hemos dado un valor refiriendonos directamente a él, lo cual se hace indicando el nombre del objeto de la clase que hemos creado seguido del atributo o método separado por un punto.

El resto de parametros al ser privados, sólo se pueden setear a través de los métodos creados con tal fin. Como se ve para este fin utilizamos sus métodos set, pasándoles por parámetro los valores que queremos que tomen estas variables.

Por último, podemos ver una sentencia System.out.println al que le pasamos el string que genera el método toString(), que muestra por pantalla dicha cadena.

Espero que esta Pildorita os haya dado una visión general de la Programación Orientada a Objetos. En las próximas pildoritas empezaremos a meternos con mayor profundidad en los diferentes conceptos que hoy hemos tocado de pasada.

Índice de Pildoritas

Share
12
Nov 14

Urdangarín sufre una "robotomía"

Ayer por la noche dediqué un buen rato a temas de posicionamiento, en concreto sobre configuraciones del robots.txt.

Un robots.txt, para los que no lo sepais, es un archivo de configuración web que indica a los buscadores algunas recomendaciones a la hora de añadir el contenido de nuestra web al buscador: el sitemap de la web, el tiempo de revisión del crawler, el contenido que no queremos que indexe...

Aunque más o menos tengo claras las configuraciones típicas, quería ver ejemplos de webs potentes para ver que cosas suelen ellos bloquear a la hora de indexar, así que utilicé los parámetros de la búsqueda de Google inurl:robots.txt filetype:txt y me puse a mirar ejemplos.

Los primeros resultados que obtení fueron el del propio Google, la Wikipedia, la Casa Blanca y, oh sorpresa, el de la Casa Real. Como soy muy escéptica sobre el código que suelen tener las webs españolas decidí echarle un ojo:

User-agent: *
Disallow: 
Disallow: /_*/
Disallow: /ES/FamiliaReal/Urdangarin/
Disallow: /CA/FamiliaReal/Urdangarin/
Disallow: /EU/FamiliaReal/Urdangarin/
Disallow: /GL/FamiliaReal/Urdangarin/
Disallow: /VA/FamiliaReal/Urdangarin/
Disallow: /EN/FamiliaReal/Urdangarin/
Sitemap: http://www.casareal.es/sitemap.xml

URL: http://www.casareal.es/robots.txt

Ni un disallow de los js o cualquier carpeta de configuración, pero oye, no ha faltado ni una referencia a las diferentes versiones de la página de Urdangarín, no vaya a ser que alguien descubra que este sinvergüenza era el cuñadísimo de nuestro monarca.

Artículo publicado en El Boletin:

Urdangarín sufre una "robotomía" (El Boletin)

Share