Existen 3 características que nos dan la razón de utilizar nuestros propios objetos en vez de depender de las funciones, librerías y globales que el lenguaje nos pone a disposición, estas son:
- Polimorfismo: utilización de las mismas operaciones en diferentes objetos de diferentes clases.
- Encapsulamiento: ocultar de entes exteriores al objeto sus atributos de forma que pueda protegerlos.
- Herencia: crear objetos más específicos que heredan los métodos y atributos básicos de una clase superior más general.
Polimorfismo
Este término significa que tiene muchas formas, esto significa que podemos realizar operaciones que funcionaran de forma diferente dependiendo del tipo o clase del objeto. Tomemos un ejemplo sencillo, imaginemos que tenemos un shopping cart, entonces definimos como queremos que se obtenga los datos del precio y del producto que se quiere, como vemos en la siguiente imagen que creamos una tupla.
Ahora que sucedería si luego se expande la funcionalidad del shopping cart y ahora se trabajan con subastas, de alguna forma deberíamos especificar los valores que se deben recibir y cómo actuar al utilizar los mismos métodos, la forma que muchos pensarían es hacer una función de la siguiente forma, sin embargo no es lo adecuado.
Cómo podemos ver en la imágen cubrimos las posibilidades del momento, sin embargo, que pasa cuando se aumentan las funcionalidades, vamos a tener que seguir actualizando este código eternamente, ahí es donde entra el polimorfismo y lo que hacemos es definir que cada objeto devuelva su precio sin importarnos el cómo lo calcula ya que es algo interno de cada clase, lo que nos quedaría de la siguiente forma:
Podemos ver entonces que es algo que nos ayuda a tener un código que sea más perdurable en el tiempo, de más fácil mantenimiento.
Encapsulamiento
Esto consiste en ocultar los detalles internos de la clase al mundo exterior, de forma que solo se pueda acceder por sus propios objetos y métodos, de esta forma podemos trabajar con clases sin necesidad de saber su funcionamiento interno, eliminando complejidad de implementación y protegiendo la lógica dentro de nuestros objetos.
También nos permite trabajar con seguridad de que los datos dentro de nuestro objeto no serán cambiados, ya que si trabajan de una forma abstracta podremos, instanciar múltiples veces y cada instancia es totalmente individual.
Veamos un ejemplo de un objeto que no está encapsulado:
Aquí vemos que a pesar que fue o1 quien hizo un set del nombre, o2 accede al mismo nombre sin haberle hecho set, esto en una aplicación sería problemático, imaginemos que necesitamos el precio de varios productos y cada uno sobrescribe el precio del anterior.
Ahora con un encapsulamiento fijémonos cómo funcionaría todo el flujo del programa.
Aquí vemos que cada objeto mantiene su nombre, de forma que sabemos que podemos trabajar con seguridad obteniendo los valores correctos de cada uno de nuestros objetos.