¡Prepárate para una lectura profunda! Hoy, nos sumergiremos en el mundo de la Programación Orientada a Objetos (POO). Es un tema avanzado de desarrollo, pero queremos que lo domines.

El término POO sugiere que este enfoque de programación prioriza los objetos. En realidad, es un poco más complejo, pero llegaremos a eso. Primero, exploremos los conceptos generales de la POO y sus inicios.

Programación Tradicional (Procedimental)

La programación tradicional suele referirse a la programación procedimental, que se basa en procedimientos y funciones. Una función es un miniprograma que recibe datos como entrada, procesa algo y puede devolver datos como resultado de los cálculos. Imagínate una cinta transportadora dentro de una caja.

Concepto de función de código
Concepto de función de código

Por ejemplo, una tienda en línea podría tener una función llamada «Validar correo electrónico«. Recibe un texto, lo compara con sus reglas y devuelve un resultado: si es una dirección de correo electrónico válida o no. Si lo es, devuelve «verdadero«, si no, «falso«.

Ejemplo de función de verificación del correo electrónico
Ejemplo de función de verificación del correo electrónico

Las funciones son útiles cuando necesitas agrupar muchos comandos en uno solo. Por ejemplo, la validación de una dirección de correo electrónico podría implicar una simple verificación de expresiones regulares o incluir múltiples comandos: consultas de diccionario, comprobaciones de bases de datos de correo no deseado e incluso comparaciones con direcciones de correo electrónico conocidas. Puedes empaquetar cualquier combinación de acciones en una función y luego invocarlas todas con un solo comando.

Limitaciones de la Programación Procedimental

La programación procedimental funciona bien para programas simples, donde un puñado de funciones pueden resolver todas las tareas. Las funciones se apilan cuidadosamente, interactúan entre sí y puedes pasar datos de una función a otra.

Por ejemplo, imagina que creas una función llamada «Registrar usuario de la tienda en línea«. Dentro de ella, necesitas verificar su dirección de correo electrónico. Llamas a la función «Validar correo electrónico» desde la función «Registrar usuario» y, según la respuesta de la función, registras al usuario o muestras un error. Esta función se utiliza en otros diez lugares. Las funciones están entrelazadas.

Ejemplo de funciones entrelazadas
Ejemplo de funciones entrelazadas

Ahora, el gerente de producto interviene y dice: «Quiero que el usuario sepa exactamente cuál es el error al ingresar la dirección de correo electrónico«. Ahora debes hacer que la función devuelva un código de error además de «verdadero» o «falso«: por ejemplo, «01» para un error tipográfico o «02″ para una dirección de correo electrónico de spam. Esto es fácil de implementar.

Modificas el comportamiento de la función: ahora devuelve un código de error en lugar de «verdadero» o «falso«, y devuelve «OK» si no hay error.

Entonces, tu código se rompe: todos los diez lugares que esperaban «verdadero» o «falso» del validador ahora reciben «OK» y se rompen como resultado.

Ejemplo de limitación de programación procedimental
Ejemplo de limitación de programación procedimental

Ahora tienes que:

  • Reescribir todas las funciones para que comprendan las nuevas respuestas del validador de direcciones.
  • Modificar el validador de direcciones para que sea compatible con los lugares antiguos, pero que devuelva códigos de error en el lugar que necesites.
  • Crear un nuevo validador que devuelva códigos de error y utilizar el antiguo validador en los lugares antiguos.

Esta tarea se puede resolver en una o dos horas.

Pero imagina que tienes cientos de estas funciones. Y necesitas hacer docenas de cambios en ellas todos los días. Además, cada cambio generalmente hace que las funciones se comporten de manera más compleja y produzcan resultados más complejos. Y cada cambio en un lugar rompe otros tres lugares. Como resultado, terminarás creando docenas de funciones clonadas que primero debes entender y luego modificar.

Esto se conoce como código espagueti y la Programación Orientada a Objetos se inventó para combatirlo.

Ejemplo de entrelazado de funciones que crean Código Espagueti
Ejemplo de entrelazado de funciones que crean Código Espagueti

Programación Orientada a Objetos

El objetivo principal de la POO es simplificar el código complejo. Para ello, el programa se divide en bloques independientes que llamamos objetos.

Un objeto no es una entidad cósmica. Es simplemente un conjunto de datos y funciones, como en la programación funcional tradicional. Puedes imaginarlo como un trozo de programa dentro de una caja cerrada. Esta caja con tapa es un objeto.

Representación de objeto en POO
Representación de objeto en POO

Los programadores acordaron que los datos dentro de un objeto se llamarían propiedades y las funciones, métodos. Pero son solo palabras; en esencia, siguen siendo variables y funciones.

Un objeto puede verse como un aparato de cocina independiente. La tetera hierve agua, la estufa calienta, la licuadora bate y la picadora de carne hace carne picada. Dentro de cada dispositivo hay un montón de cosas: motores, controladores, botones, resortes, fusibles, pero tú no piensas en ellos. Presionas los botones del panel de cada aparato y hace lo que se espera. Y gracias al trabajo conjunto de estos aparatos, obtienes la cena.

Los objetos se caracterizan por cuatro palabras: encapsulación, abstracción, herencia y polimorfismo. Si te interesa saber qué son, te invitamos a leer:

Encapsulación, Abstracción, Herencia, Polimorfismo

Encapsulación

Un objeto es independiente: cada objeto está organizado de manera que los datos que necesita residen dentro de ese objeto, no en algún lugar externo del programa. Por ejemplo, si tengo un objeto «Usuario«, contendrá todos los datos sobre el usuario: nombre, dirección y todo lo demás. Y también contendrá los métodos «Verificar correo» o «Suscribirse a boletín«.

Abstracción

Un objeto tiene una «interfaz»: tiene métodos y propiedades a los que podemos acceder desde fuera del objeto. Así como podemos presionar un botón en una licuadora. La licuadora tiene muchas cosas dentro que la hacen funcionar, pero en el panel principal solo hay un botón. Ese botón es la interfaz abstracta.

En el programa, podemos decir: «Eliminar usuario«. En el lenguaje de POO, sería «usuario.eliminar()«, es decir, accedemos al objeto «usuario» y llamamos al método «eliminar«. Lo bueno es que no nos importa cómo se realizará la eliminación: la POO nos permite no pensar en ello en el momento de la llamada.

Por ejemplo, dos programadores trabajan en una tienda en línea: uno escribe el módulo de pedido y el otro, el módulo de entrega. El primero tiene un método «cancelar» en el objeto «pedido«. Y el segundo necesita cancelar el pedido debido a la entrega. Y simplemente escribe: «pedido.cancelar()«. No le importa cómo el otro programador implementará la cancelación: qué correos enviará, qué escribirá en la base de datos, qué advertencias mostrará.

Concepto de objeto e interfaces

Concepto de objeto e interfaces

Herencia

Capacidad de copiar. La POO permite crear muchos objetos a imagen y semejanza de otro objeto. Esto te permite evitar copiar y pegar código doscientas veces, escribirlo correctamente una vez y luego usarlo muchas veces.

Por ejemplo, puedes tener un objeto ideal «Usuario«: en él, describes todo lo que puede sucederle a un usuario. Puedes tener propiedades: nombre, edad, dirección, número de tarjeta. Y puede tener métodos «Dar descuento«, «Verificar pedido«, «Encontrar pedidos«, «Llamar«.

Basado en este usuario ideal, puedes crear un «Comprador Iván» real. Al crearlo, tendrá todas las propiedades y métodos que definiste para el comprador ideal, además puede tener algunos propios, si lo deseas.

Los programadores llaman a los objetos instancias de clases.

Polimorfismo

Un lenguaje común para todos. En POO, es importante que todos los objetos se comuniquen entre sí en un lenguaje que comprendan. Y si diferentes objetos tienen un método «Eliminar«, debería hacer exactamente eso y escribirse de la misma manera en todas partes. No podemos permitir que un objeto lo tenga como «Eliminar» y otro como «Borrar«.

Sin embargo, internamente, los métodos de los objetos pueden implementarse de diferentes maneras. Por ejemplo, eliminar un producto es mostrar una advertencia y luego marcar el producto en la base de datos como eliminado. Y eliminar un usuario es cancelar sus compras, darse de baja del boletín y archivar el historial de sus compras. Los eventos son diferentes, pero no es importante para el programador. Simplemente tiene un método «Eliminar()» y confía en él.

Cambiar objeto pero interfaz no cambia

Cambiar objeto pero interfaz no cambia

Este enfoque permite programar cada módulo independientemente de los demás. Lo principal es pensar de antemano cómo se comunicarán los módulos entre sí y según qué reglas. Con este enfoque, puedes mejorar el funcionamiento de un módulo sin afectar a los demás; para todo el programa no importa lo que haya dentro de cada bloque, si las reglas para trabajar con él siguen siendo las mismas.

Ventajas y Desventajas de la POO

La Programación Orientada a Objetos tiene muchas ventajas, y por eso la mayoría de los programadores modernos utilizan este enfoque.

  • El código se vuelve visualmente más simple y fácil de leer. Cuando todo está dividido en objetos y tienen un conjunto claro de reglas, puedes comprender de inmediato de qué es responsable cada objeto y de qué está compuesto.
  • Menos código duplicado. Si en la programación tradicional una función cuenta caracteres repetitivos en una matriz unidimensional y otra en una matriz bidimensional, gran parte de su código será idéntico. En POO, esto se resuelve mediante herencia.
  • Los programas complejos son más fáciles de escribir. Cada programa grande se puede dividir en varios bloques, darles un contenido mínimo y luego completar cada bloque en detalle uno por uno.
  • Mayor velocidad de escritura. Inicialmente, puedes crear rápidamente los componentes necesarios dentro del programa para obtener un prototipo mínimo viable.

Ahora, las desventajas:

  • Difícil de entender y comenzar a usar. El enfoque de la POO es mucho más complejo que la programación procedimental tradicional: necesitas conocer mucha teoría antes de escribir una sola línea de código.
  • Requiere más memoria. Los objetos en POO constan de datos, interfaces, métodos y mucho más, lo que ocupa mucha más memoria que una simple variable.
  • El rendimiento del código a veces puede ser menor. Debido a las peculiaridades del enfoque, algunas cosas pueden implementarse de manera más compleja de lo que podrían ser. Por lo tanto, a veces sucede que un programa POO funciona más lentamente que un programa procedimental (aunque con las potencias de procesamiento modernas, esto preocupa a pocas personas).

Próximos Pasos

A continuación, hablaremos sobre clases, objetos y todo lo demás que es importante en la POO. ¡Prepárate, será interesante!

Serie de Guías Relacionadas a POO:

  1. Explicación Programación Orientada a Objetos
  2. ¿Qué son las Clases en Programación Orientada a Objetos?
  3. ¿Qué son los Objetos en Programación Orientada a Objetos?
  4. Clases y Funciones en Programación Orientada a Objetos
  5. Atributos y Métodos en Programación Orientada a Objetos
  6. Abstracciones e Interfaces: ¿Por qué son Necesarias?
  7. ¿Qué son los Getters y Setters en Programación?

Categorizado en:

Fundamentos,