Skip to content

Commit 5ab2bab

Browse files
authored
Merge pull request #7992 from idiegorojas/main
#29 - Python
2 parents 3b84e9c + 2f74381 commit 5ab2bab

File tree

2 files changed

+274
-0
lines changed

2 files changed

+274
-0
lines changed
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
"""
2+
#29 - Principio SOLID: Segregacion de interfaces en Python
3+
"""
4+
# "Los clientes no deberian versen forzados a depender de interfaces que no utilizan."
5+
# Es mejor tener varias interfaces especificas y pequeñas
6+
# Esto evita que las clases dependan de metodos que no necesitan.
7+
8+
"""
9+
Beneficios de aplicar el ISP
10+
"""
11+
# Código más mantenible: Las interfaces pequeñas y específicas son más fáciles de mantener y modificar.
12+
# Mayor cohesión: Cada interfaz tiene una responsabilidad clara y concreta.
13+
# Menor acoplamiento: Las clases solo dependen de las interfaces que realmente necesitan.
14+
# Mayor flexibilidad: Es más fácil combinar interfaces pequeñas para crear comportamientos complejos.
15+
# Testing más sencillo: Las interfaces pequeñas facilitan la creación de mocks y stubs para pruebas.
16+
17+
18+
19+
"""
20+
Violacion del principio.
21+
"""
22+
# Creamos un programa para para dos impresoras, una nueva y una vieja
23+
# El problema aquí es que ImpresoraVieja está obligada a implementar métodos que no puede realizar.
24+
25+
26+
from abc import ABC, abstractmethod
27+
28+
class ImpresionDispositivo(ABC):
29+
@abstractmethod
30+
def imprimir(self, documento):
31+
pass
32+
33+
@abstractmethod
34+
def escanear(self, documento):
35+
pass
36+
37+
@abstractmethod
38+
def enviar_fax(self, documento):
39+
pass
40+
41+
@abstractmethod
42+
def grapar(self, documento):
43+
pass
44+
45+
46+
class ImpresoraModerna(ImpresionDispositivo):
47+
def imprimir(self, documento):
48+
print(f"Imprimiendo: {documento}")
49+
50+
def escanear(self, documento):
51+
print(f"Escaneando: {documento}")
52+
53+
def enviar_fax(self, documento):
54+
print(f"Enviando fax: {documento}")
55+
56+
def grapar(self, documento):
57+
print(f"Grapando: {documento}")
58+
59+
60+
class ImpresoraVieja(ImpresionDispositivo):
61+
def imprimir(self, documento):
62+
print(f"Imprimiendo: {documento}")
63+
64+
def escanear(self, documento):
65+
# Esta impresora no puede escanear
66+
raise NotImplementedError("Esta impresora no puede escanear")
67+
68+
def enviar_fax(self, documento):
69+
# Esta impresora no puede enviar fax
70+
raise NotImplementedError("Esta impresora no puede enviar fax")
71+
72+
def grapar(self, documento):
73+
# Esta impresora no puede grapar
74+
raise NotImplementedError("Esta impresora no puede grapar")
75+
76+
77+
78+
"""
79+
Aplicar correctamente el principio y Ejercicio Extra
80+
"""
81+
from abc import ABC, abstractmethod
82+
83+
class Impresora(ABC):
84+
@abstractmethod
85+
def imprimir(self, documento):
86+
pass
87+
88+
89+
class Escaner(ABC):
90+
@abstractmethod
91+
def escanear(self, documento):
92+
pass
93+
94+
95+
class FaxDevice(ABC):
96+
@abstractmethod
97+
def enviar_fax(self, documento):
98+
pass
99+
100+
101+
class Grapadora(ABC):
102+
@abstractmethod
103+
def grapar(self, documento):
104+
pass
105+
106+
107+
class ImpresoraModerna(Impresora, Escaner, FaxDevice, Grapadora):
108+
def imprimir(self, documento):
109+
print(f"Imprimiendo: {documento}")
110+
111+
def escanear(self, documento):
112+
print(f"Escaneando: {documento}")
113+
114+
def enviar_fax(self, documento):
115+
print(f"Enviando fax: {documento}")
116+
117+
def grapar(self, documento):
118+
print(f"Grapando: {documento}")
119+
120+
121+
class ImpresoraVieja(Impresora):
122+
def imprimir(self, documento):
123+
print(f"Imprimiendo: {documento}")
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
"""
2+
# 30 - Prinicipio SOLID: Inversion de dependencias.
3+
"""
4+
# Lo modulos de alto nivel no deben depender de los modulos de bajo nivel. Ambos deben depender de abstracciones
5+
# Las abstracciones no deben depender de los detalles. Los detalles deben depender de las abstracciones.
6+
# Debemos programar hacia interfaces o clases abstractas en lugar de implementaciones concretas.
7+
8+
"""
9+
Beneficios
10+
"""
11+
# Desacoplamiento: Las clases de alto nivel no dependen de las implementaciones específicas.
12+
# Flexibilidad: Facilita cambiar implementaciones sin modificar código existente.
13+
# Facilita pruebas unitarias: Permite usar mocks o stubs para las dependencias.
14+
# Mejor diseño: Fomenta pensar en términos de interfaces y comportamientos, no implementaciones.
15+
16+
17+
"""
18+
Ejemplo de violacion del principio
19+
"""
20+
# Interruptor depende directamente de LuzConcreta
21+
# Si queremos usar otro tipo de luz, tendríamos que modificar la clase Interruptor
22+
# Es difícil realizar pruebas unitarias
23+
24+
class LuzPasillo:
25+
def encender(self):
26+
print("Luz encendida")
27+
28+
def apagar(self):
29+
print('Luz apagada')
30+
31+
class Interruptor:
32+
def __init__(self):
33+
self.luz = LuzPasillo()
34+
35+
def operar(self):
36+
self.luz.encender()
37+
38+
39+
"""
40+
Ejemplo aplicando el principio
41+
"""
42+
from abc import ABC, abstractmethod
43+
44+
class DispositivoElectronico(ABC):
45+
@abstractmethod
46+
def encender(self):
47+
pass
48+
49+
def apagar(self):
50+
pass
51+
52+
53+
class Luz(DispositivoElectronico):
54+
def encender(self):
55+
print('Luz encendida.')
56+
57+
def apagar(self):
58+
print('Luz apagada')
59+
60+
61+
class Ventilador(DispositivoElectronico):
62+
def encender(self):
63+
print('Ventilador encendido')
64+
65+
def apagar(self):
66+
print('Ventilador apagado')
67+
68+
69+
class Interruptor:
70+
def __init__(self, dispositivo: DispositivoElectronico):
71+
self.dispositivo = dispositivo
72+
73+
def operar(self, encender=True):
74+
if encender:
75+
self.dispositivo.encender()
76+
else:
77+
self.dispositivo.apagar()
78+
79+
luz = Luz()
80+
ventilador = Ventilador()
81+
82+
interruptor_luz = Interruptor(luz)
83+
interruptor_ventilador = Interruptor(ventilador)
84+
85+
interruptor_luz.operar(encender=True)
86+
interruptor_luz.operar(encender=False)
87+
interruptor_ventilador.operar(encender=True)
88+
89+
90+
"""
91+
Extra
92+
"""
93+
from abc import ABC, abstractmethod
94+
95+
class Notificar(ABC):
96+
@abstractmethod
97+
def enviar_notificacion(self):
98+
pass
99+
100+
@abstractmethod
101+
def cancelar_notificacion(self):
102+
pass
103+
104+
105+
class Email(Notificar):
106+
def enviar_notificacion(self):
107+
print('Se ha enviado el email.')
108+
109+
def cancelar_notificacion(self):
110+
print('Se ha cancelado el email.')
111+
112+
class Push(Notificar):
113+
def enviar_notificacion(self):
114+
print('Se ha enviado el Push.')
115+
116+
def cancelar_notificacion(self):
117+
print('Se ha cancelado el Push.')
118+
119+
class Sms(Notificar):
120+
def enviar_notificacion(self):
121+
print('Se ha enviado el SMS.')
122+
123+
def cancelar_notificacion(self):
124+
print('Se ha cancelado el SMS.')
125+
126+
127+
class SistemaNotificaciones:
128+
def __init__(self, notificacion: Notificar):
129+
self.notificacion = notificacion
130+
131+
def procesar_notificacion(self, enviar=True):
132+
if enviar:
133+
self.notificacion.enviar_notificacion()
134+
else:
135+
self.notificacion.cancelar_notificacion()
136+
137+
138+
email = Email()
139+
push = Push()
140+
sms = Sms()
141+
142+
enviar_email = SistemaNotificaciones(email)
143+
enviar_push = SistemaNotificaciones(push)
144+
enviar_sms = SistemaNotificaciones(sms)
145+
146+
enviar_email.procesar_notificacion(enviar=True)
147+
enviar_email.procesar_notificacion(enviar=False)
148+
enviar_push.procesar_notificacion(enviar=True)
149+
enviar_push.procesar_notificacion(enviar=False)
150+
enviar_sms.procesar_notificacion(enviar=True)
151+
enviar_sms.procesar_notificacion(enviar=False)

0 commit comments

Comments
 (0)