Ir al contenido

Paradigmas de Programación

Publicado: a las  10:00 a. m.

Paradigmas de la programación

¿Qué es un paradigma de programación?

Un paradigma de programación es como un estilo o una forma de pensar para resolver problemas con código. Es el enfoque que usamos para organizar y estructurar nuestras ideas cuando programamos.

Imaginate que tenés que armar un mueble de Hyper Theuelche o en Chuar. Podés:

¡Todos los caminos te llevan al mismo mueble armado, pero la forma de pensarlo es diferente!

En este artículo vamos a explorar los tres paradigmas más importantes que vas a usar en tu carrera como programador.


Programación Estructurada

Programación Estructurada

La programación estructurada es como seguir un mapa para llegar a un destino.

Supongamos que querés ir de tu casa al parque Manuel Belgrano. Un mapa te muestra el camino a seguir, con instrucciones paso a paso:

  1. Salir de tu casa
  2. Caminar 3 cuadras hacia el norte
  3. Girar a la izquierda
  4. Caminar 2 cuadras hacia el oeste
  5. Llegar al parque

En la programación estructurada, el mapa es el código y las instrucciones son las líneas de código que se ejecutan una después de la otra, en un orden lógico.

El código se divide en bloques o módulos, como las secciones del mapa, y cada bloque tiene una función específica, como “caminar hacia el norte” o “girar a la izquierda”.

Las tres estructuras fundamentales

La programación estructurada se basa en tres herramientas fundamentales:

  1. Secuencias: Son las instrucciones que se ejecutan una después de la otra, en un orden lógico.

  2. Decisiones (o Condicionales): Son las instrucciones que permiten tomar decisiones basadas en condiciones específicas, como “si” o “si no”. Por ejemplo, “si es mayor de edad, entonces…”

  3. Iteraciones (o Bucles): Son las instrucciones que se repiten mientras se cumple una condición específica. Por ejemplo, “mientras que la variable sea menor que 10, hacé tal cosa…”

Herramientas adicionales

Además, la programación estructurada también utiliza:

Ejemplo práctico: Control de temperatura

Imaginate que estás programando un sistema de control de temperatura para un invernadero en El Calafate (¡donde hace frío!). Acá tenés un ejemplo en Python:

def controlar_temperatura(temperatura_actual):
    """
    Controla la temperatura del invernadero
    """
    # Secuencia: definimos las temperaturas ideales
    temp_minima = 15
    temp_maxima = 25

    # Decisión: verificamos la temperatura
    if temperatura_actual < temp_minima:
        encender_calefaccion()
        print(f"🔥 Calefacción encendida. Temp: {temperatura_actual}°C")
    elif temperatura_actual > temp_maxima:
        encender_ventilacion()
        print(f"💨 Ventilación encendida. Temp: {temperatura_actual}°C")
    else:
        print(f"✅ Temperatura óptima: {temperatura_actual}°C")

def encender_calefaccion():
    # Aquí iría el código para activar el relé de la calefacción
    pass

def encender_ventilacion():
    # Aquí iría el código para activar el relé de ventilación
    pass

# Iteración: monitoreamos la temperatura cada hora
temperaturas = [12, 18, 22, 28, 20, 16]

for temp in temperaturas:
    controlar_temperatura(temp)

Ventajas de la programación estructurada:


Programación Funcional

Programación Funcional

Imaginate que querés hacer una torta. En la programación funcional, cada ingrediente es una función que hace una cosa específica, como mezclar harina, agregar azúcar o batir huevos.

Cada función recibe ingredientes (entradas) y produce un resultado (salida). No cambia los ingredientes originales, solo crea un nuevo resultado.

Principios clave

  1. Funciones puras: Una función siempre devuelve el mismo resultado para las mismas entradas, sin efectos secundarios.
  2. Inmutabilidad: Los datos no se modifican, se crean nuevos datos.
  3. Composición: Las funciones se combinan como piezas de LEGO para crear soluciones más complejas.

Ejemplo práctico: Procesamiento de datos de sensores

Imaginate que tenés varios sensores de temperatura en diferentes puntos de una planta industrial y necesitás procesar esos datos:

# Funciones puras: siempre devuelven lo mismo para las mismas entradas
def celsius_a_fahrenheit(celsius):
    """Convierte temperatura de Celsius a Fahrenheit"""
    return (celsius * 9/5) + 32

def filtrar_temperaturas_criticas(temperaturas, limite=30):
    """Filtra temperaturas que superan el límite"""
    return list(filter(lambda t: t > limite, temperaturas))

def calcular_promedio(numeros):
    """Calcula el promedio de una lista de números"""
    return sum(numeros) / len(numeros) if numeros else 0

def aplicar_descuento_termico(temperatura, descuento=0.5):
    """Aplica un factor de corrección a la temperatura"""
    return temperatura - descuento

# Composición: combinamos funciones para resolver el problema
def procesar_datos_sensores(temperaturas_celsius):
    """
    Procesa datos de sensores:
    1. Filtra temperaturas críticas
    2. Aplica corrección térmica
    3. Convierte a Fahrenheit
    4. Calcula promedio
    """
    # Cada paso crea nuevos datos sin modificar los originales
    criticas = filtrar_temperaturas_criticas(temperaturas_celsius)
    corregidas = list(map(aplicar_descuento_termico, criticas))
    en_fahrenheit = list(map(celsius_a_fahrenheit, corregidas))
    promedio = calcular_promedio(en_fahrenheit)

    return {
        'criticas': criticas,
        'corregidas': corregidas,
        'fahrenheit': en_fahrenheit,
        'promedio': promedio
    }

# Uso
sensores = [22, 31, 28, 35, 26, 33, 29]
resultado = procesar_datos_sensores(sensores)

print(f"Temperaturas críticas: {resultado['criticas']}")
print(f"Promedio corregido: {resultado['promedio']:.2f}°F")

Ventajas de la programación funcional:


Programación Orientada a Objetos (POO)

Poo

La programación orientada a objetos es como crear moldes o plantillas para representar cosas del mundo real en tu código.

Imaginate que estás creando un sistema de control para una planta industrial. Tenés diferentes dispositivos: sensores, actuadores, válvulas, motores. Cada uno tiene características propias y puede hacer cosas específicas.

Conceptos fundamentales

  1. Clase: Es el molde o plantilla que define cómo es un objeto. Por ejemplo, la clase “Sensor” define qué características y habilidades tiene un sensor.

  2. Objeto (o Instancia): Es una creación específica a partir de una clase. Por ejemplo, “sensor_temperatura_1” es un objeto de la clase Sensor.

  3. Atributos: Son las características del objeto. Por ejemplo, un sensor tiene: nombre, ubicación, valor actual, unidad de medida.

  4. Métodos: Son las acciones que puede hacer el objeto. Por ejemplo, un sensor puede: leer valor, calibrarse, enviar alerta.

Los 4 pilares de la POO

  1. Encapsulamiento: Guardar datos y métodos juntos, protegiendo la información interna.
  2. Abstracción: Mostrar solo lo necesario, ocultar la complejidad.
  3. Herencia: Crear nuevas clases basadas en clases existentes.
  4. Polimorfismo: Diferentes objetos pueden responder al mismo mensaje de formas distintas.

Ejemplo práctico: Sistema de monitoreo industrial

class Sensor:
    """Clase base para todos los sensores"""

    def __init__(self, nombre, ubicacion, unidad):
        # Atributos: características del sensor
        self.nombre = nombre
        self.ubicacion = ubicacion
        self.unidad = unidad
        self.valor_actual = 0
        self.activo = True

    # Métodos: acciones que puede hacer el sensor
    def leer_valor(self, nuevo_valor):
        """Lee y almacena un nuevo valor del sensor"""
        if self.activo:
            self.valor_actual = nuevo_valor
            return True
        return False

    def obtener_estado(self):
        """Devuelve el estado actual del sensor"""
        estado = "🟢 Activo" if self.activo else "🔴 Inactivo"
        return f"{self.nombre} ({self.ubicacion}): {self.valor_actual}{self.unidad} - {estado}"

    def desactivar(self):
        """Desactiva el sensor"""
        self.activo = False

# Herencia: SensorTemperatura hereda de Sensor
class SensorTemperatura(Sensor):
    """Sensor especializado en temperatura"""

    def __init__(self, nombre, ubicacion):
        # Llamamos al constructor de la clase padre
        super().__init__(nombre, ubicacion, "°C")
        self.temp_minima = -10
        self.temp_maxima = 50

    def verificar_rango(self):
        """Verifica si la temperatura está en rango seguro"""
        if self.valor_actual < self.temp_minima:
            return f"⚠️ ALERTA: Temperatura muy baja ({self.valor_actual}°C)"
        elif self.valor_actual > self.temp_maxima:
            return f"⚠️ ALERTA: Temperatura muy alta ({self.valor_actual}°C)"
        else:
            return f"✅ Temperatura normal ({self.valor_actual}°C)"

class SensorPresion(Sensor):
    """Sensor especializado en presión"""

    def __init__(self, nombre, ubicacion):
        super().__init__(nombre, ubicacion, " bar")
        self.presion_maxima = 10

    def verificar_presion(self):
        """Verifica si la presión es segura"""
        if self.valor_actual > self.presion_maxima:
            return f"🚨 PELIGRO: Presión crítica ({self.valor_actual} bar)"
        return f"✅ Presión normal ({self.valor_actual} bar)"

# Polimorfismo: diferentes sensores, misma interfaz
class SistemaMonitoreo:
    """Sistema que gestiona múltiples sensores"""

    def __init__(self):
        self.sensores = []

    def agregar_sensor(self, sensor):
        """Agrega un sensor al sistema"""
        self.sensores.append(sensor)

    def mostrar_todos(self):
        """Muestra el estado de todos los sensores"""
        print("\n📊 ESTADO DEL SISTEMA")
        print("=" * 50)
        for sensor in self.sensores:
            print(sensor.obtener_estado())

# Uso del sistema
sistema = SistemaMonitoreo()

# Creamos objetos (instancias) de diferentes sensores
temp1 = SensorTemperatura("Temp-Caldera", "Sala de máquinas")
temp2 = SensorTemperatura("Temp-Ambiente", "Oficina")
presion1 = SensorPresion("Presion-Linea-1", "Tubería principal")

# Agregamos sensores al sistema
sistema.agregar_sensor(temp1)
sistema.agregar_sensor(temp2)
sistema.agregar_sensor(presion1)

# Simulamos lecturas
temp1.leer_valor(85)
temp2.leer_valor(22)
presion1.leer_valor(7.5)

# Mostramos el estado
sistema.mostrar_todos()

# Verificamos rangos
print("\n🔍 VERIFICACIÓN DE SEGURIDAD")
print("=" * 50)
print(temp1.verificar_rango())
print(temp2.verificar_rango())
print(presion1.verificar_presion())

Ventajas de la POO:


Comparación práctica: El mismo problema, tres soluciones

Veamos cómo resolver el mismo problema (calcular el promedio de temperaturas válidas) con los tres paradigmas:

Versión Estructurada

def calcular_promedio_estructurado(temperaturas):
    total = 0
    contador = 0

    # Iteramos sobre cada temperatura
    for temp in temperaturas:
        # Decisión: solo contamos temperaturas válidas
        if temp >= -50 and temp <= 100:
            total += temp
            contador += 1

    # Calculamos y retornamos el promedio
    if contador > 0:
        return total / contador
    return 0

temps = [22, -100, 25, 28, 150, 24]
print(f"Promedio: {calcular_promedio_estructurado(temps):.2f}°C")

Versión Funcional

def es_temperatura_valida(temp):
    return -50 <= temp <= 100

def calcular_promedio_funcional(temperaturas):
    validas = list(filter(es_temperatura_valida, temperaturas))
    return sum(validas) / len(validas) if validas else 0

temps = [22, -100, 25, 28, 150, 24]
print(f"Promedio: {calcular_promedio_funcional(temps):.2f}°C")

Versión Orientada a Objetos

class AnalizadorTemperaturas:
    def __init__(self, temp_min=-50, temp_max=100):
        self.temp_min = temp_min
        self.temp_max = temp_max
        self.temperaturas = []

    def agregar_temperatura(self, temp):
        if self.temp_min <= temp <= self.temp_max:
            self.temperaturas.append(temp)

    def calcular_promedio(self):
        if self.temperaturas:
            return sum(self.temperaturas) / len(self.temperaturas)
        return 0

analizador = AnalizadorTemperaturas()
temps = [22, -100, 25, 28, 150, 24]

for temp in temps:
    analizador.agregar_temperatura(temp)

print(f"Promedio: {analizador.calcular_promedio():.2f}°C")

¿Cuándo usar cada paradigma?

Usá Programación Estructurada cuando:

Usá Programación Funcional cuando:

Usá Programación Orientada a Objetos cuando:


🎮 Desafío para vos

Ejercicio 1: Creá una clase Valvula que tenga:

Ejercicio 2: Escribí una función pura que reciba una lista de presiones y devuelva solo las que están en rango seguro (0-10 bar).

Ejercicio 3: Hacé un programa estructurado que controle un semáforo (verde, amarillo, rojo) con tiempos específicos.


Conclusión

Los paradigmas de programación son herramientas en tu caja de herramientas como programador. No hay uno “mejor” que otro, sino que cada uno es más adecuado para diferentes situaciones.

En tu carrera de Automatización y Control de Procesos Industriales, vas a usar los tres:

¡Lo importante es conocerlos todos y saber cuándo aplicar cada uno! 🚀

Próximo paso: Practicá creando pequeños programas con cada paradigma. Empezá simple y andá aumentando la complejidad a medida que te sientas más cómodo.

¿Tenés dudas? ¡Preguntá en clase o dejá un comentario! 💬