Me había decidido a escribir sobre patrones de diseño ya
que es un tema que actualmente estoy estudiando, sin embargo una de las
primeras cosas que aprendí con los patrones de diseño es a favorecer la
composición (HAS A) sobre la herencia (IS A), con lo cual quizás si no se
conoce lo suficiente se subestime el poder de la herencia, así que lo mejor
será comenzar con los principios básicos de programación, aunque por el momento
solo tengo planeado abarcar la herencia y el polimorfismo.
Los principios básicos de la programación orientada a
objetos son:
·
Abstracción
·
Encapsulación
·
Polimorfismo
·
Herencia
Conocer estos principios no te hará un buen programador,
pero él no conocerlos bien definitivamente será un obstáculo para seguir
avanzando como programador. La abstracción a grandes rasgos te permite ignorar
el "cómo funciona" y concentrarte en "que hace", dicho de
otra manera no necesitas conocer el funcionamiento de un objeto para hacer uso
del mismo, como sucede en algunos casos cotidianos, por ejemplo tu no necesitas
saber cómo funciona internamente una computadora para utilizarla, lo mismo
sucede con la abstracción no es necesario saber cómo funciona un objeto para
hacer uso del mismo.
public class ComputerUser { private Computer computer; public ComputerUser(Computer computer) { this.computer = computer; } public Document createDocument(String name) { return this.computer.createDocument(name); } public void writeDocument(Document doc, String text) { this.computer.writeDocument(doc, text); } public void closeDocument(Document doc) { this.computer.Close(); } }
En este caso nosotros no conocemos como el objeto
"computer" realiza su trabajo sin embargo conocemos sus métodos y los
utilizamos, pero no entraré en más detalles.
Encapsulamiento básicamente se refiere al aislamiento de
los métodos y propiedades del objeto, a los cuales no tendremos acceso sino
solamente mediante métodos específicos definidos por el objeto, retomando el
ejemplo anterior podemos tener acceso al objeto "computer" pero no
tenemos acceso al atributo "ram", ya que podría ser peligroso que se
tenga acceso a la misma, tampoco entraré en más detalles.
La herencia que es nuestro tema principal consiste en la
reutilización de código de una clase a otra, es decir una clase que deriva de
otra obtiene algunos de los atributos y métodos de la primera, existe la
herencia simple y la herencia múltiple, como nos concentraremos en Java solo
trataremos la herencia simple.
El Polimorfismo es la habilidad de un método de comportarse
de diferentes formas, es una de las características más usadas en la
programación orientada a objetos, es el concepto que más se me dificulta
explicar así que lo explicare más a detalle en código.
En ocasiones cuando codificamos tenemos una tendencia a
repetir código de una clase a otra, lo cual a futuro se vuelve un dolor de
cabeza, ya que un cambio a ese código significa modificar más de una clase, aunque
esto se puede evitar con un buen diseño orientado a objetos, veamos un ejemplo más
práctico, ¡fabriquemos un carro!, fabriquemos el clásico tsuru.
package CarTest; public class Tsuru { private String model; private int year; public Tsuru() { this.model = "Tsuru"; this.year = 2012; } public void turnOn() { System.out.println("Start the engine"); } public void turnOff() { System.out.println("Stop the engine"); } public void accelerate() { System.out.println("Speed Up"); } public void brake() { System.out.println("Stop the Car"); } public void speedChange() { System.out.println("Change the velocity with Clutch"); } public String getModel() { return this.model; } public int getYear() { return this.year; } public String toString() { return "I'm a " + this.model + " of " + this.year; } }
Perfecto tenemos nuestro tsuru, este puede acelerar, frenar
y cambiar de velocidad, tiene todo lo necesario para dar una vuelta, lo cual es
tentador pero primero fabriquemos otro carro, esta vez un chevy... Un momento
prácticamente tendremos que repetir todo el código de tsuru a chevy ya que son
capaces de realizar las mismas acciones, repetir el código suena a una tarea
tediosa y aburrida, así que lo mejor será buscar otras alternativas es momento
de hacer uso de la herencia.
Por cierto si te preguntas por la palabra "this"
está es utilizada para hacer referencia a la instancia actual, e igual lo
tratare en otro post.
Creamos una clase abstracta que contenga los métodos que
comparten "turnOn", "turnOff", "accelerate", "brake",
"speedChange", "getModel", "getYear", "toString",
un momento... nuestro carro puede ser automático o estándar, eso significa que
nuestro método "speedChange" va a variar dependiendo del tipo carro,
podemos dejarlo así y confiar en que el programador que ocupe esta clase
abstracta se acuerde de modificar el método en un carro automático, eso no
suena muy bien, lo mejor será obligar al programador a escribir su propia
implementación haciendo al método abstracto, eso suena mucho mejor, así no tendremos que preocuparnos por un
carro automático intentando cambiar de velocidad con un Clutch inexistente.
package CarTest; public abstract class Car { private String model; private int year; public Car(String model, int year) { this.model = model; this.year = year; } public void turnOn() { System.out.println("Start the engine"); } public void turnOff() { System.out.println("Stop the engine"); } public void accelerate() { System.out.println("Speed Up"); } public void brake() { System.out.println("Stop the Car"); } public abstract void speedChange(); public String getModel() { return this.model; } public int getYear() { return this.year; } public String toString() { return "I'm a " + this.model + " of " + this.year; } }
Quizás te preguntarás porque en el constructor de la
clase abstracta "Car" recibe de parámetros el Modelo y el año, esto
es porque en Herencia los atributos y métodos que se heredan son los marcados
con el "scope" public, protected y default, los públicos pueden ser
heredados por cualquier otra clase dentro o fuera del "package", los
default solo por clases dentro del "package" y los protected por
clases dentro del "package" y por clases fuera del "package"
pero solo a la primer subclase, hablaré de esto en otra ocasión. Así que no
podemos modificar los atributos modelo y año directamente ya que son privados,
así que delegamos esa responsabilidad al constructor que si puede modificar
estos atributos.
Ahora modifiquemos nuestra clase Tsuru para que herede de
Car, y creemos nuestra clase Chevy.
package CarTest; public class Tsuru extends Car { public Tsuru() { super("Tsuru", 2012); } public void speedChange() { System.out.println("Change the velocity with Clutch"); } }
package CarTest; public class Chevy extends Car { public Chevy() { super("Chevy", 2008); } public void speedChange() { System.out.println("Automatic change of velocity"); } }
Al llamar al método "super" lo que hacemos es
llamar al constructor de la clase base, es decir el constructor de la clase que
heredamos, en este caso la clase Car, y le pasamos los argumentos modelo y año.
Perfecto nuestras clases ahora son bastante compactas y
tienen todas las funcionalidades de un carro, por el momento dejaremos el tema
hasta aquí, pero seguiremos con él en la segunda parte de este post, ya que no
hemos terminado con la herencia, no hemos visto polimorfismo, y además tenemos
que probarar nuestro carros.
Happy Coding...
Excelente muy bien explicado!! Kokubunji.
ResponderEliminar