Skip to content

Commit

Permalink
Merge pull request mouredev#7197 from mrodara/mrodara/main
Browse files Browse the repository at this point in the history
#29-Python
  • Loading branch information
Roswell468 authored Dec 1, 2024
2 parents 72be212 + af75775 commit e789507
Show file tree
Hide file tree
Showing 2 changed files with 352 additions and 0 deletions.
207 changes: 207 additions & 0 deletions Roadmap/29 - SOLID ISP/python/mrodara.py
Original file line number Diff line number Diff line change
@@ -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="[email protected]", 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="[email protected]", 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)
145 changes: 145 additions & 0 deletions Roadmap/30 - SOLID DIP/python/mrodara.py
Original file line number Diff line number Diff line change
@@ -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)

0 comments on commit e789507

Please sign in to comment.