Qué es la Programación Orientada a Objetos: los principales conceptos, explicados para todos los públicos

La 'POO' es, hoy en día, uno de los principales paradigmas de programación de software. Puede parecer un concepto muy abstracto, pero —si bien es cierto que se basa en la abstracción— no es difícil de entender

Objetos
4 comentarios Facebook Twitter Flipboard E-mail

La programación orientada a objetos, o POO, es una metodología de diseño y programación que se basa en la organización de datos y comportamientos en estructuras llamadas "objetos". Aunque puede sonar técnico al principio, este enfoque revoluciona la forma en que creamos y estructuramos software…

…al alinear más estrechamente nuestro código con cómo vemos y categorizamos el mundo real, la POO nos permite escribir software más organizado, reutilizable y fácil de entender. Repasemos los conceptos

Un vistazo a…
La carrera de programador en 2017 y en el futuro (con Javier Santana)

0. Abstracción: simplificando la Realidad

La abstracción es uno de los pilares fundamentales de la programación orientada a objetos: nos permite modelar el mundo real en términos de código, eligiendo qué propiedades y comportamientos son esenciales para nuestro software y cuáles pueden ser ignorados. Esto hace que el diseño del software sea más manejable, manteniendo el enfoque en la funcionalidad clave.

En la programación, la abstracción a menudo se logra mediante la creación de clases y objetos. Estas clases sirven como plantillas o modelos que capturan la esencia de algo, sin entrar minuciosamente en todos los detalles (o atributos).

1. ¿Qué es un objeto?

En el mundo real, estamos rodeados de objetos: tu taza de café, tu teléfono, tu bicicleta. Estos objetos tienen características (color, tamaño, modelo) y comportamientos (una taza contiene líquido, un teléfono puede hacer llamadas). En POO, modelamos estas entidades reales como "objetos" en código.

Por ejemplo, considera una sencilla definición de un coche:

class Coche:
   # Constructor de la clase
   def init(self, marca, modelo):
self.marca = marca
       self.modelo = modelo
# Método para describir el coche
def describir(self):
   return f"Este coche es un {self.marca} {self.modelo}"

Aquí, marca y modelo son características, mientras que describir es un comportamiento.

2. Clases: Los moldes de los objetos

La definición anterior (Coche) es lo que llamamos una clase. Piensa en la clase Coche como un plano que nos dice cómo debería ser cada coche que salga de la fábrica en términos de programación.

O podemos plantearlo en términos más domésticos: imaginemos que estás en la cocina, listo para hacer galletas. Tienes un molde de galletas que te ayudará a darles una forma específica. Este molde es lo que en POO llamamos una clase. Es una definición o plantilla que nos dice cómo se verán y comportarán nuestras galletas.

Clasesobjetos

Ahora bien, cuando usas el molde para hacer una galleta, esa galleta individual es un objeto. Aunque proviene de un molde común, cada galleta es única y puede tener sus propias particularidades, como chispas de chocolate o trocitos de nuez.

3. Creación de objetos: instanciando una clase

Una vez que tengas una clase, puedes crear objetos específicos o instancias de esa clase. Siguiendo con nuestro ejemplo:

mi_coche = Coche("Toyota", "Corolla")
print(mi_coche.describir())  # Salida: Este coche es un Toyota Corolla

4. Atributos y métodos

Atributos Un mismo objeto 'Chico' puede tener varios atributos, diferentes o en común con respecto a otros objetos de la misma clase

Piensa en cómo describirías a tu mejor amigo: tiene nombre, edad, color de ojos, hobbies, etc. Estas características individuales son similares a los atributos en POO. Es decir, son las propiedades específicas que un objeto (como nuestra galleta) puede tener.

Además de tener características, las personas pueden hacer cosas: cantar, bailar, correr, etc. En POO, estos comportamientos o acciones son los métodos. Son acciones que un objeto puede realizar.

Monigote El mismo objeto 'monigote' haciendo uso de tres métodos distintos…

En nuestros ejemplos anteriores, 'Coche', 'marca' y 'modelo' son atributos, mientras que 'describir()' es un método.

5. Herencia: Tomando lo mejor de otros

Cuando hablamos de familias, a menudo escuchamos que alguien "ha heredado" el color de ojos de su madre o el talento musical de su padre.

En POO, la herencia permite que una clase (recuerda, el molde de galletas) tome atributos y métodos de otra clase. Es como si una nueva receta de galletas tomara ingredientes de una receta anterior y agregara algo más.

Herencia

Supongamos que queremos tener una clase CocheElectrico que comparta algunas características con Coche pero que tenga algunas adicionales:

class CocheElectrico(Coche):
   def init(self, marca, modelo, autonomia):
       super().init(marca, modelo)
       self.autonomia = autonomia
def autonomia_restante(self, distancia_recorrida):
   return self.autonomia - distancia_recorrida

El CocheElectrico es un tipo especial de Coche, pero tiene una característica adicional: autonomia. También tiene un método adicional para determinar la autonomía restante.

6. Polimorfismo: Una función, muchas formas

El polimorfismo se refiere a la capacidad de diferentes clases de ser tratadas como instancias de la misma clase a través de la herencia. Es una forma elegante de decir que diferentes objetos pueden realizar una acción de la misma manera.

Considerando las clases anteriores, aunque Coche y CocheElectrico son diferentes, ambos pueden usar el mismo método describir(). Este es un simple ejemplo de polimorfismo.

7. Encapsulamiento: Protegiendo nuestro código

Encapsulamiento

El encapsulamiento es la práctica de ocultar los detalles internos de cómo una clase realiza sus acciones. Imagina que tienes una mochila donde guardas tus cosas. Cuando la cierras, no necesitas saber exactamente cómo está todo organizado dentro.

En POO, el encapsulamiento es como esa mochila: protege y oculta los detalles internos de un objeto, permitiendo que interactuemos con él de manera simple y segura. En Python, por ejemplo, usamos guiones bajos para denotar atributos o métodos privados:

class Coche:
   def __init__(self, marca, modelo):
       self._codigo_secreto = "12345"
       self.marca = marca
       self.modelo = modelo

Aquí, _codigo_secreto es un atributo protegido, que idealmente no debería ser accedido directamente fuera de la clase.

Pero, ¿por qué deciemos que es más seguro recurrir al encapsulamiento? Veamos:

  1. Protección de datos internos: El encapsulamiento permite restringir el acceso directo a determinados atributos o métodos de una clase. Esto significa que podemos proteger y controlar cómo se accede y modifica la información interna de un objeto, evitando manipulaciones indebidas.
  2. Flexibilidad y mantenimiento: Si en el futuro necesitas cambiar la forma en que se implementa una característica particular, gracias al encapsulamiento, puedes hacerlo sin alterar el código que utiliza esa clase. Esto reduce el riesgo de errores cuando se hacen modificaciones.

8. Composición: construyendo objetos a partir de otros

Composicion

La composición implica construir clases utilizando otras clases como partes. Imagina construir un robot usando piezas individuales; cada pieza es esencial para la función completa del robot.

Por ejemplo, un objeto Coche puede estar compuesto objetos como Motor, Ruedas o Chasis.

9. Interfaces: un contrato entre clases

Las interfaces juegan un papel fundamental en muchos lenguajes de programación orientada a objetos. Puedes pensar en una interfaz como un contrato que una clase decide firmar. Este contrato estipula que la clase implementará ciertos métodos, pero no dicta cómo deben implementarse esos métodos. En otras palabras, la interfaz define qué se debe hacer, pero deja el cómo hacerlo a la clase que la implementa.

Imagina un control remoto universal: tiene botones para encender, apagar, subir el volumen, bajar el volumen, etc. No importa la marca o el modelo de televisión, si deseas que ese televisor sea compatible con el control remoto universal, debe cumplir con ciertas funciones básicas. De manera similar, una interfaz define un conjunto de métodos que cualquier clase que implemente esa interfaz debe tener.

Controlremoto

Vamos a ver un ejemplo simplificado usando Python. Aunque Python no tiene un soporte directo para interfaces como otros lenguajes (como Java), podemos simularlo usando clases abstractas:

from abc import ABC, abstractmethod
class Encendible(ABC):
@abstractmethod
def encender(self):
   pass

@abstractmethod
def apagar(self):
   pass
class Bombilla(Encendible):
def encender(self):
   print("Bombilla encendida!")

def apagar(self):
   print("Bombilla apagada!")

Aquí, Encendible es nuestra interfaz que dicta que cualquier objeto que pueda ser encendido y apagado debe tener los métodos encender() y apagar(). La clase Bombilla implementa esta interfaz y define cómo se enciende y se apaga una bombilla.

Las interfaces son una herramienta poderosa en la POO, ya que promueven la reutilización de código y aseguran que ciertas clases tengan comportamientos esperados, actuando como un estándar que debe seguirse. Además, ayudan a desacoplar el código, permitiendo que los sistemas sean más flexibles y adaptables a cambios futuros.

Epílogo: Historia de la Programación Orientada a Objetos (POO)

La programación orientada a objetos (POO) se desarrolló como una respuesta a las crecientes necesidades y desafíos de la ingeniería de software, buscando proporcionar estructuras más modulares, reutilizables y fácilmente mantenibles.

  1. 1960s - Simula: El origen de la POO se encuentra en el lenguaje de programación Simula, que introdujo los primeros conceptos de programación orientados a objetos, aunque el propio término "orientado a objetos" aún no había sido acuñado.
  2. 1970s - Smalltalk: En la década de 1970, el lenguaje Smalltalk se convirtió en el primer lenguaje de programación totalmente orientado a objetos. Introdujo conceptos como clases, instancias, herencia y encapsulamiento, y popularizó la POO.
  3. 1980s - C++: Durante la década de 1980, Bjarne Stroustrup desarrolló C++, que añadió características orientadas a objetos al lenguaje C. C++ jugó un papel crucial en hacer de la POO una técnica dominante en la ingeniería de software, dada su compatibilidad con C y su poderosa combinación de programación procedural y orientada a objetos.
  4. 1990s - Java: En la década de 1990, Sun Microsystems introdujo Java, diseñado con una orientación a objetos desde su núcleo. Java llevó la POO a la vanguardia de la ingeniería de software a gran escala y al desarrollo web, gracias a su portabilidad y su promesa de "Escribirlo una vez, ejecutarlo en cualquier sitio".
  5. Otros Lenguajes: A lo largo de los años, varios otros lenguajes han incorporado soporte para POO, incluidos Python, Ruby, C#, PHP y muchos más. Estos lenguajes han adaptado y evolucionado los principios básicos de POO para satisfacer diferentes necesidades y paradigmas.

Imágenes | Marcos Merino mediante IA

En Genbeta | Bill Gates cuenta cómo consiguió convertirse en un gran desarrollador: este es su principal consejo

Comentarios cerrados
Inicio