class ModeloIA:def__init__(self):self.datos = []self.modelo =Nonedef cargar_datos(self, ruta):# Mezcla lógica de lectura de datos con procesamientowithopen(ruta, "r") as f:self.datos = [line.strip().split(",") for line in f]self.limpiar_datos()def limpiar_datos(self):# Limpieza de datos dentro del mismo móduloself.datos = [fila for fila inself.datos iflen(fila) ==3]def entrenar_modelo(self):# Lógica de entrenamiento dentro del mismo móduloself.modelo =sum(len(fila) for fila inself.datos)def predecir(self, entrada):returnself.modelo *len(entrada) ifself.modelo elseNone
class ModeloIA:def__init__(self):self.modelo =Nonedef entrenar(self, datos):# Simulación de entrenamientoself.modelo =sum(len(fila) for fila in datos)def predecir(self, entrada):returnself.modelo *len(entrada) ifself.modelo elseNone# Acoplamiento fuerte: depende directamente de ModeloIAclass ProcesadorDatos:def__init__(self):self.datos = []self.modelo = ModeloIA()def cargar_datos(self, ruta):withopen(ruta, "r") as f:self.datos = [line.strip().split(",") for line in f]self.limpiar_datos()self.modelo.entrenar(self.datos) # Acoplamiento fuerte: entrenar directamente aquídef limpiar_datos(self):self.datos = [fila for fila inself.datos iflen(fila) ==3]def predecir(self, entrada):returnself.modelo.predecir(entrada) # Llama directamente al modelo
class ProcesadorDatos:def init(self):self.datos = []def cargar_datos(self, ruta):withopen(ruta, "r") as f:self.datos = [line.strip().split(",") for line in f]self.limpiar_datos()def limpiar_datos(self):self.datos = [fila for fila inself.datos iflen(fila) ==3]def obtener_datos(self):returnself.datosclass ModeloIA:def init(self):self.modelo =Nonedef entrenar(self, datos):self.modelo =sum(len(fila) for fila in datos)def predecir(self, entrada):returnself.modelo *len(entrada) ifself.modelo elseNoneprocesador = ProcesadorDatos()procesador.cargar_datos("datos.csv")datos = procesador.obtener_datos()modelo = ModeloIA()modelo.entrenar(datos)prediccion = modelo.predecir([1, 2, 3])print(prediccion)
RECUERDA
Reutilizar código NO es ❌ copiar y pegar ❌
El código reutilizable debe diseñarse para que funcione bien en distintos contextos sin modificaciones.
Por ejemplo, al realizar pruebas automáticas estamos cambiando el contexto:
Llamando a funciones de forma aislada
Pasando datos falsos
Simulando el comportamiento de librerías externas
Principios de Diseño de Software
Son directrices que ayudan a crear software mantenible, reutilizable y escalable.
Aplicables en el diseño de sistemas orientados a objetos y arquitectura de software.
Algunos principios fundamentales…
DRY (Don’t Repeat Yourself)
Evitar duplicación de código
KISS (Keep It Simple, Stupid)
Diseñar soluciones simples y comprensibles
YAGNI (You Ain’t Gonna Need It)
No implementar funcionalidades innecesarias
Separation of Concerns
Dividir el software en módulos con responsabilidades claras
Para poder diseñar y comprender sistemas complejos necesitamos visualizarlos usando herramientas que nos permitan ver solamente la información más relevante.
Lenguajes visuales (diagramas)
UML
UML (Unified Modeling Language) es un lenguaje de modelado visual estándar para representar el diseño de sistemas de software.
Facilita la comunicación entre desarrolladores, analistas y otros interesados en el proyecto.
Permite modelar estructuras, comportamientos e interacciones dentro de un sistema.
Es independiente del lenguaje de programación y se usa en múltiples dominios.
Las clases se representan en UML con un rectángulo dividido en tres secciones:
Nombre de la clase (Parte superior)
Atributos (Parte media)
Métodos (Parte inferior)
Modificadores de visibilidad
Símbolo
Tipo
Descripción
+
Público
Accesible desde cualquier clase
-
Privado
Solo accesible dentro de la propia clase
#
Protegido
Accesible dentro de la clase y sus subclases
~
Paquete
Accesible dentro del mismo paquete o módulo
Modificadores de visibilidad
Recuerda que en el código los atributos privados usan el prefijo __ y los protegidos _
Propiedades
Las propiedades se representarán con el modificador {property} junto al nombre de la propiedad.
Si la propiedad es de solo lectura se indicará con {readonly}.
Esto es una convención establecida en la asignatura.
Propiedades
class Persona:def__init__(self, nombre: str, dni: str):self.__nombre = nombre # Variable privada para almacenar el nombreself.__dni = dni # Variable privada para almacenar el DNI@propertydef nombre(self) ->str:returnself.__nombre@nombre.setterdef nombre(self, nuevo_nombre: str):self.__nombre = nuevo_nombre@property# Solo lectura, no se define un setterdef dni(self) ->str:returnself.__dni