Mostrando entradas con la etiqueta Conceptos POO. Mostrar todas las entradas
Mostrando entradas con la etiqueta Conceptos POO. Mostrar todas las entradas

lunes, 24 de septiembre de 2012

POO: Pilares de la programación orientada a objetos



En un libro aprendí un tip bastante útil para recordar los pilares de la programación orientada a objetos. Solo hay que recordar el acrónimo: PIE. En las entrevistas es muy típico que se pregunte alguno de los principios de la programación orientada a objetos. Si se pregunta de manera general, se puede dar una buena impresión explicando cada uno de los pilares de manera elocuente.

Polymorphism (Poliformismo): la habilidad de una variable de un tipo específico de ser usada para referenciar objetos de diferentes tipos, y automáticamente llamar el método que es específico al tipo del objeto que la variable referencia. El beneficio del poliformismo es que resulta fácil agregar nuevas clases de objetos derivados sin quebrar el código invocador. En cortas palabras, cuando se invoca un método de un objeto sin saber su tipo específico, y sucede lo correcto, a eso llamamos poliformismo. Ejemplo:

public void printArea(Figure figure) {
   System.out.println(figure.getArea());
}

Figure figure = new Square(); // Square extends from Figure
printArea(figure); // Should print axa (a=side of a square);

Inheritance (Herencia): Este debería ser el principio más fácil de explicar. Consiste en incluir el comportamiento (métodos) y estado (variables) de una clase base, en una clase derivada. El beneficio principal de la herencia es que provee un mecanismo formal para la reutilización de código.

Encapsulation (Encapsulación): Se refiere a mantener todos los miembros relacionados (variables y métodos) juntos en un objeto. Los objetos deben ocultar la funcionalidad que es interna del mundo exterior. Esto se realiza al declarar ciertos métodos y variables como privadas en la clase. La buena encapsulación mejora la modularidad del código al prevenir que los objetos interactuen entre sí de maneras insospechadas, lo cual hace más fácil futuros desarrollos y refactorizaciones más sencillas.

jueves, 2 de diciembre de 2010

Diferencia entre Clase Abstracta e Interface


Potencial pregunta de entrevista de trabajo. La diferencia puede parecer obvia en el código, pero en términos de funcionalidad existe un traslapo donde tenemos que detenernos por un momento a reflexionar, si es que no lo hemos hecho, por qué debemos usar una opción o la otra.

Lo primero que recordamos de una clase abstracta es que no podemos instanciarla. La clase abstracta se usa como interfaz de las subsecuentes clases que harán conversión hacia arriba ("upcasting"). Podemos describir el upcasting como la acción de declarar una variable de una clase base (abstracta en la mayoría de los casos), pero instanciando una implementación de la misma. Esto da vida al comportamiento polifórmico.

MyAbstract myAbstract = new MyImplementation();

Veamos un ejemplo de una clase abstracta reloj.


public abstract class Watch {

/* Instance variables */

protected int seconds;
protected int minutes;
protected int hours;

/* Constructors */

public Watch() {

}

public Watch(int h, int m, int s) {
hours = h;
minutes = m;
seconds = s;
}

// Must override this method.
abstract public void showTime();

/*Getters and setters for the time components.*/

public int getSeconds() {
return seconds;
}

public void setSeconds(int seconds) {
this.seconds = seconds;
}

public int getMinutes() {
return minutes;
}

public void setMinutes(int minutes) {
this.minutes = minutes;
}

public int getHours() {
return hours;
}

public void setHours(int hours) {
this.hours = hours;
}
}


Y ahora la implementación de un reloj dijital.


public class DigitalWatch extends Watch {

public DigitalWatch(int h, int m, int s) {
super(h,m,s);
}

public void showTime() {
System.out.println(hours +":" + minutes + ":" + seconds);
}

public static void main(String[] args) {
Watch myWatch = new DigitalWatch(5, 30, 20);
myWatch.showTime(); // Prints "5:30:20".
}
}


Si intentamos replicar este diseño con el uso de una interfaz vemos que necesitamos mover el código antes localizado en la clase base Watch en la implementación de DigitalWatch.


public interface WatchI {

public void showTime();

}


public class DigitalWatchI implements WatchI{

protected int seconds;
protected int minutes;
protected int hours;

public void showTime() {
System.out.println(hours +":" + minutes + ":" + seconds);
}

public DigitalWatchI(int h, int m, int s) {
hours = h;
minutes = m;
seconds = s;
}

/*Getters and setters for the time components.*/

public int getSeconds() {
return seconds;
}

public void setSeconds(int seconds) {
this.seconds = seconds;
}

public int getMinutes() {
return minutes;
}

public void setMinutes(int minutes) {
this.minutes = minutes;
}

public int getHours() {
return hours;
}

public void setHours(int hours) {
this.hours = hours;
}

public static void main(String[] args) {
WatchI myWatch = new DigitalWatchI(5, 30, 20);
myWatch.showTime(); // Prints "5:30:20".
}
}


Las interfaces en Java se utilizan primordialmente para separar la interfaz de la implementación en una manera más estricta de como lo hace las clases abstractas. Una interfaz no permite del todo algún nivel de implementación en los métodos. Con la clase abstracta si podemos heredar la implementación de una clase a otra.

En resumen:

Classe Abstracta Interface
Contiene tanto métodos ejecutables como métodos
abstractos.
No tiene código de implementación.
Todos sus métodos son abstractos.
Una clase solo puede extender de una única clase abstracta. Una clase puede implementar n número de interfaces.
Puede tener variables de instancia, constructores y cualquiera de los tipos de visibildiad: public, private, protected, ninguno (aka package). No puede tener variables de instancia o constructores y solo puede tener métodos públicos o package.