1
+ ### Principio SOLID de Sustitución de Liskov (Liskov Substitution Principle, LSP)
2
+
3
+ '''
4
+ LSP establece que: Un objeto de una subclase debe ser sustituible por un objeto de su clase base
5
+ sin alterar el correcto funcionamiento del programa.
6
+
7
+ LSP se centra en garantizar que las subclases no modifiquen el comportamiento esperado de la clase base.
8
+ En otras palabras, cualquier clase hija debe ser capaz de reemplazar a su clase padre sin introducir errores o
9
+ comportamientos inesperados.
10
+ '''
11
+ '''
12
+ Ventajas:
13
+ - Mejora la reutilización de código.
14
+ - Aporta coherencia en la jerarquía de clases.
15
+ - Ayuda a evitar la dependencia de la implementación.
16
+ '''
17
+
18
+ # Ejemplo que viola LSP
19
+ # Clase Base
20
+ class CuentaBancaria ():
21
+ def __init__ (self , saldo ):
22
+ self .saldo = saldo
23
+
24
+ def retirar (self , monto ):
25
+ if monto <= self .saldo :
26
+ self .saldo -= monto
27
+ else :
28
+ raise ValueError ("Saldo insuficiente para retirar de la cuenta" )
29
+
30
+ # Clase Derivada
31
+ class CuentaAhorros (CuentaBancaria ):
32
+
33
+ def retirar (self , monto ):
34
+ raise NotImplementedError ("No se puede realizar retirada de la cuenta ahorro" )
35
+
36
+ # Al aplicar polimorfismo en este caso está violando el principio de Sustitución de Liskov
37
+ '''
38
+ CuentaAhorros no puede ser sustituida por CuentaBancaria sin alterar
39
+
40
+ def procesar_retiro(cuenta, monto):
41
+ cuenta.retirar(monto)
42
+
43
+ cuenta = CuentaBancaria(1000)
44
+ procesar_retiro(cuenta, 100) # Funciona correctamente
45
+
46
+ cuenta_ahorros = CuentaAhorros(1000)
47
+ procesar_retiro(cuenta_ahorros, 100) # Lanza NotImplementedError
48
+ '''
49
+
50
+ # Arreglemos el ejemplo empleando abstracciones para restricciones específicas
51
+ from abc import ABC , abstractmethod
52
+
53
+ class CuentaBancaria (ABC ):
54
+
55
+ def __init__ (self , saldo ):
56
+ self .saldo = saldo
57
+
58
+ @abstractmethod
59
+ def retirar (self , monto ):
60
+ pass
61
+
62
+ class CuentaCorriente (CuentaBancaria ):
63
+ def retirar (self , monto ):
64
+ if monto <= self .saldo :
65
+ self .saldo -= monto
66
+ print ("Retirada de efectivo realizada correctamente" )
67
+ else :
68
+ raise ValueError ("Su saldo es inferior a la cantidad a retirar, abortando operación" )
69
+
70
+ class CuentaAhorros (CuentaBancaria ):
71
+ def retirar (self , monto ):
72
+ if monto > self .saldo :
73
+ raise ValueError ("Saldo insuficiente, abortando operación" )
74
+
75
+ if monto >= 500 :
76
+ raise ValueError ("La retirada máxima para este tipo de cuenta es de 500€" ) # Restricción específica para esta clase
77
+
78
+ self .saldo -= monto
79
+
80
+ # Prueba de funcionamiento correcto
81
+ def procesar_retirada (cuenta , monto ):
82
+ try :
83
+ cuenta .retirar (monto )
84
+ print (f"Proceso finalizado, su saldo actual tras la operación es de { cuenta .saldo } €" )
85
+ except ValueError as e :
86
+ print (e )
87
+
88
+ c1 = CuentaCorriente (1000 )
89
+ c2 = CuentaAhorros (2000 )
90
+
91
+ procesar_retirada (c1 , 500 ) # Funciona correctamente
92
+ procesar_retirada (c2 , 200 ) # Funciona correctamente
93
+ procesar_retirada (c2 , 700 ) # Lanza ValueError
94
+
95
+ ### EJERCICIO EXTRA
96
+
97
+ from abc import ABC , abstractmethod
98
+
99
+ class Vehicle (ABC ):
100
+ def __init__ (self , type , max_speed , speed = 0 ):
101
+ self .type = type
102
+ self .max_speed = max_speed
103
+ self .speed = speed if speed <= max_speed else max_speed
104
+
105
+ @abstractmethod
106
+ def speed_up (self , qty ):
107
+ pass
108
+
109
+ @abstractmethod
110
+ def speed_down (self , qty ):
111
+ pass
112
+
113
+
114
+ class Car (Vehicle ):
115
+ def speed_up (self , qty ):
116
+ if self .speed + qty <= self .max_speed :
117
+ self .speed += qty
118
+ print (f"Acelerar terminado, velocidad actual: { self .speed } " )
119
+ else :
120
+ raise ValueError ("La cantidad a acelerar supera la velocidad máxima del vehículo" )
121
+
122
+ def speed_down (self , qty ):
123
+ if self .speed - qty >= 0 :
124
+ self .speed -= qty
125
+ print (f"Frenar terminado, velocidad actual: { self .speed } " )
126
+ else :
127
+ self .speed = 0
128
+ print ("Vehículo parado" )
129
+
130
+
131
+ class Truck (Vehicle ):
132
+ def speed_up (self , qty ):
133
+ if self .speed + qty <= self .max_speed :
134
+ self .speed += qty
135
+ print (f"Acelerar terminado, velocidad actual: { self .speed } " )
136
+ else :
137
+ raise ValueError ("La cantidad a acelerar supera la velocidad máxima del camión" )
138
+
139
+ def speed_down (self , qty ):
140
+ if self .speed - qty >= 0 :
141
+ self .speed -= qty
142
+ print (f"Frenar terminado, velocidad actual: { self .speed } " )
143
+ else :
144
+ self .speed = 0
145
+ print ("Vehículo parado" )
146
+
147
+
148
+ class ElectricCar (Vehicle ):
149
+ def speed_up (self , qty ):
150
+ if self .speed + qty <= self .max_speed :
151
+ self .speed += qty
152
+ print (f"Acelerar terminado, velocidad actual: { self .speed } " )
153
+ else :
154
+ raise ValueError ("La cantidad a acelerar supera la velocidad máxima del vehículo eléctrico" )
155
+
156
+ def speed_down (self , qty ):
157
+ if self .speed - qty >= 0 :
158
+ self .speed -= qty
159
+ print (f"Frenar terminado, velocidad actual: { self .speed } " )
160
+ else :
161
+ self .speed = 0
162
+ print ("Vehículo parado" )
163
+
164
+
165
+ # Realización de pruebas
166
+ def test_speed (vehicle ):
167
+ print (f"Inicio de las pruebas con { vehicle .type } " )
168
+ try :
169
+ vehicle .speed_up (25 )
170
+ vehicle .speed_down (5 )
171
+ vehicle .speed_up (vehicle .max_speed + 1 )
172
+ vehicle .speed_down (vehicle .speed )
173
+ except ValueError as e :
174
+ print (e )
175
+ print ("-" * 60 )
176
+
177
+ cars = [
178
+ Car ("Ferrari F50" , 300 , 125 ),
179
+ Truck ("Mercedes-Benz Actros" , 150 , 80 ),
180
+ ElectricCar ("Tesla Model S" , 120 , 125 )
181
+ ]
182
+
183
+ for car in cars :
184
+ test_speed (car ) # Realizar pruebas con cada tipo de vehículo
185
+
186
+
187
+ ### FIN EJERCICIO EXTRA
188
+
189
+
190
+ ### FIN Principio SOLID de Sustitución de Liskov (Liskov Substitution Principle, LSP)
0 commit comments