From 4d69a4259589489d75efbe67d36314190e5e4989 Mon Sep 17 00:00:00 2001 From: Manuel Jesus Rodriguez Arabi Date: Sat, 30 Nov 2024 23:08:22 +0100 Subject: [PATCH 1/2] feat: #29-Python Reto #29-Python realizado por mrodara --- Roadmap/29 - SOLID ISP/python/mrodara.py | 207 +++++++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 Roadmap/29 - SOLID ISP/python/mrodara.py diff --git a/Roadmap/29 - SOLID ISP/python/mrodara.py b/Roadmap/29 - SOLID ISP/python/mrodara.py new file mode 100644 index 0000000000..14e232bc4e --- /dev/null +++ b/Roadmap/29 - SOLID ISP/python/mrodara.py @@ -0,0 +1,207 @@ +### Principio de Segregación de Interfaces (Interface Segregation Principle, ISP) + +''' +Este principio establece que: + +"Ningún cliente debería depender de métodos que no utiliza." + +Esto significa que las interfaces (o clases abstractas en Python) deben diseñarse de manera que los clientes que +las implementan no se vean forzados a definir métodos innecesarios o irrelevantes. + +Ventajas: + ++ Reduce el acoplamiento ++ Hace el código más modular ++ Facilitan la implementación +''' + +# Ejemplo que viola el principio + +from abc import ABC, abstractmethod + +class Vehicle(ABC): + + @abstractmethod + def drive(self): + pass + + @abstractmethod + def pilot(self): + pass + + @abstractmethod + def navigate(self): + pass + +class Car(Vehicle): + + def drive(): + print("El coche está en marcha") + + def pilot(self): + raise NotImplementedError("Un coche no puede volar") + + def navigate(self): + raise NotImplementedError("Un coche no puede navegar por el mar") + +''' +En este ejemplo los principales problemas son: +- El cliente (Car) debe implementar métodos que no utiliza (pilot y navigate) +- El cliente debe manejar excepciones innecesarias +''' + +# Fin Ejemplo que viola el principio + +# Rediseño para no violar el ISP + +class Driveable(ABC): + + @abstractmethod + def drive(self): + pass + +class Pilotable(ABC): + + @abstractmethod + def pilot(self): + pass + +class Navigateable(ABC): + + @abstractmethod + def navigate(self): + pass + + +class Car(Driveable): + + def drive(self): + print("El cocche está en marcha") + +class Plane(Pilotable): + + def pilot(self): + print("El avión está volando") + +class Ship(Navigateable): + + def navigate(self): + print("El barco se encuentra navegando en alta mar") + + +# Fin Rediseño para no violar el ISP + +## EJERCICIO EXTRA + +class PrinterBW(ABC): + + @abstractmethod + def print_bn(self): + pass + +class PrinterColor(ABC): + + @abstractmethod + def print_color(self): + pass + +class Maileable(ABC): + + @abstractmethod + def send_mail(self): + pass + +class Faxeable(ABC): + + @abstractmethod + def send_fax(self): + pass + +class BwPrinter(PrinterBW): + + def print_bn(self): + print("Imprimiendo documento en Blanco/Negro") + +class ColorPrinter(PrinterColor): + + def print_color(self): + print("Imprimiendo documento en Color") + +class MultiFunction(PrinterBW, PrinterColor, Maileable, Faxeable): + + def print_bn(self): + print("Imprimiendo documento en Blanco/Negro") + + def print_color(self): + print("Imprimiendo documento en Color") + + def send_mail(self, to="correo@correo.es", subject="Test", body="This is a mail test"): + print(f"Enviando correo electrónico a {to} con asunto {subject} y mensaje {body}") + + def send_fax(self, destination_number="+345557890", content="This is a fax test"): + print(f"Enviando fax a {destination_number} con contenido {content}") + + +# Batería de pruebas + +def test_bw_printer(): + printer = BwPrinter() + printer.print_bn() # Debería imprimir en blanco y negro + +def test_color_printer(): + printer = ColorPrinter() + printer.print_color() # Debería imprimir en color + +def test_multi_function_print_bn(): + printer = MultiFunction() + printer.print_bn() # Debería imprimir en blanco y negro + +def test_multi_function_print_color(): + printer = MultiFunction() + printer.print_color() # Debería imprimir en color + +def test_multi_function_send_mail(): + printer = MultiFunction() + printer.send_mail(to="example@mail.com", subject="Prueba", body="Esto es una prueba") + +def test_multi_function_send_fax(): + printer = MultiFunction() + printer.send_fax(destination_number="+123456789", content="Esto es una prueba de fax") + +def test_no_extra_methods_bw_printer(): + printer = BwPrinter() + try: + printer.print_color() + except AttributeError: + print("Error esperado: 'BwPrinter' no tiene método 'print_color'") + +def test_no_extra_methods_color_printer(): + printer = ColorPrinter() + try: + printer.print_bn() + except AttributeError: + print("Error esperado: 'ColorPrinter' no tiene método 'print_bn'") + + +print("Pruebas de BwPrinter:") +test_bw_printer() +test_no_extra_methods_bw_printer() + +print("\nPruebas de ColorPrinter:") +test_color_printer() +test_no_extra_methods_color_printer() + +print("\nPruebas de MultiFunction:") +test_multi_function_print_bn() +test_multi_function_print_color() +test_multi_function_send_mail() +test_multi_function_send_fax() + + +## FIN EJERCICIO EXTRA + + + + + +### FIN Principio de Segregación de Interfaces (Interface Segregation Principle, ISP) \ No newline at end of file From af757759b9fc5f4dfca7740009a7e79cf4dfb7ea Mon Sep 17 00:00:00 2001 From: Manuel Jesus Rodriguez Arabi Date: Sat, 30 Nov 2024 23:46:39 +0100 Subject: [PATCH 2/2] feat: #30-Python Reto #30-Python realizado por mrodara --- Roadmap/30 - SOLID DIP/python/mrodara.py | 145 +++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 Roadmap/30 - SOLID DIP/python/mrodara.py diff --git a/Roadmap/30 - SOLID DIP/python/mrodara.py b/Roadmap/30 - SOLID DIP/python/mrodara.py new file mode 100644 index 0000000000..11aaa70305 --- /dev/null +++ b/Roadmap/30 - SOLID DIP/python/mrodara.py @@ -0,0 +1,145 @@ +### Principio de Inversión de Dependencias (Dependency Inversion Principle, DIP) + +''' +Este principio establece que: + +Los módulos de alto nivel NO deben depender de los módulos de bajo nivel. Ambos deben depender de abstracciones. + +Las abstracciones NO deben depender de los detalles. Los detalles DEBEN depender de las abstracciones. + +En resumen, el DIP promueve que las clases principales (alto nivel) dependan de interfaces o abstracciones, +en lugar de depender directamente de clases concretas (bajo nivel). +''' + +''' +Ventajas: + ++ Reduce el acoplamiento: + Los módulos de alto nivel no dependen de los detalles específicos de implementación. ++ Facilita el mantenimiento: + Los detalles de implementación pueden cambiar sin afectar a las clases principales. ++ Aumenta la flexibilidad y la extensibilidad: + Es más sencillo sustituir o añadir implementaciones concretas al depender de abstracciones. + +''' + +# EJEMPLO QUE VIOLA EL PRINCIPIO + +class CreditCardPayment(): + + def proccess_payment(self, amount): + print(f"Procesando pago con tarjeta de crédito: {amount} €") + +class OrderProccesor(): + + def __init__(self): + self.payment_proccessor = CreditCardPayment() + + def proccess_order(self, amount): + self.payment_proccessor.proccess_payment(amount=amount) + +''' +Problemas detectados: + ++ Dependencia directa: + OrderProcessor está acoplada directamente a CreditCardPayment. + No se puede usar otro método de pago sin modificar OrderProcessor. ++ Falta de flexibilidad: + Si necesitas añadir PayPalPayment o CryptoPayment, tendrás que modificar el código de OrderProcessor. +''' + +# FIN EJEMPLO QUE VIOLA EL PRINCIPIO + +# REDISEÑO PARA CUMPLIR CON EL PRINCIPIO +from abc import ABC, abstractmethod + +class PaymentProccessor(ABC): + + @abstractmethod + def proccess_payment(self, amount): + pass + +class CreditCardPayment(PaymentProccessor): + + def proccess_payment(self, amount): + print(f"Procesando pago con tarjeta de crédito: {amount} €") + +class PayPalPayment(PaymentProccessor): + + def proccess_payment(self, amount): + print(f"Procesando el pago mediante Paypal: {amount} €") + +class BizumPayment(PaymentProccessor): + + def proccess_payment(self, amount): + print(f"Procesando el pago mediante Bizum: {amount} €") + + +# Clase de Alto nivel +class OrderProccessor(): + + def __init__(self, payment_proccessor): + self.payment_proccessor = payment_proccessor + + def proccess_order(self, amount): + self.payment_proccessor.proccess_payment(amount=amount) + +order = OrderProccessor(CreditCardPayment()) +order.proccess_order(amount=100) + +order = OrderProccessor(PayPalPayment()) +order.proccess_order(amount=200) + +order = OrderProccessor(BizumPayment()) +order.proccess_order(amount=300) + +# FIN REDISEÑO PARA CUMPLIR CON EL PRINCIPIO + +## EJERCICIO EXTRA + +# CLASE ABSTRACTA +class Notifier(ABC): + + @abstractmethod + def send_notification(self, message): + pass + +#Específicas +class EmailNotifier(Notifier): + + def send_notification(self, message): + print(f"Enviando eamil con el mensaje {message}") + +class PushNotifier(Notifier): + + def send_notification(self, message): + print(f"Enviando mensaje Push con texto: {message}") + +class SmsNotifier(Notifier): + def send_notification(self, message): + print(f"Enviando mensaje SMS con texto: {message}") + +# Alto nivel +class NotificationSender(): + + def __init__(self, notifier: Notifier): + self.notifier = notifier + + def send_notification(self, message): + self.notifier.send_notification(message) + + +# Batería de pruebas +email_sender = NotificationSender(EmailNotifier()) +email_sender.send_notification("Hola soy un Email") + +push_sender = NotificationSender(PushNotifier()) +push_sender.send_notification("Hola soy un Push") + +sms_sender = NotificationSender(SmsNotifier()) +sms_sender.send_notification("Hola soy un SMS") + + +## FIN EJERCICIO EXTRA + +### FIN Principio de Inversión de Dependencias (Dependency Inversion Principle, DIP) \ No newline at end of file