Introduccion
¿En resumne que son los principios de SOLID?
Bueno los principios de la codificacion de SOLID es un acronimo hecho por Robert C. Martin y se referie a 5 conveciones diferentes de codificacion
Lo que el sugieres es que al seguir estos principios su codigo puede mejorar en confiabilidad, estructurado y su consistencia logica
Los principios son
- El principio de responsabilidad única (SRP)
- El Principio Abierto-Cerrado (OCP)
- El principio de sustitución de Liskov (LSP)
- El principio de segregación de la interfaz (ISP)
- El principio de inversión de dependencia (DIP)
Estos son una lista de buenas practicas desarrollada a lo largo de los años y se agrupan en siglas al igual que otros terminos como: DRY don’t you repeat, o tambien KISS mantelo pequeño y simple
Principio de unica responsabilidad
“Una clase debe tener solo una razon para cambiar”
que esto se refiere a que cada funcion del codigo solo debe tener una y solo una unica repsonsabilidad, que en resumen tu funcion debe hacer solo unica cosa al hacer mas de dos cosas en la funcion ya seria necesario dividirla
Ejemplo sin unica responsabilidad:
def get_num_and_bigger(list_of_items):
list_of_numbers = []
# create list of only numbers
for item in list_of_items:
if isinstance(item, int):
list_of_numbers.append(item)
print(list_of_numbers)
# find bigger number
bigger_number = max(list_of_numbers)
print(bigger_number)
get_num_and_bigger([1, 2, "pepe", 9, 10, 6, 7, 8])
Ejemplo con unica responsabilidad:
def get_only_numbers(list_of_items):
list_of_numbers = []
for item in list_of_items:
if isinstance(item, int):
list_of_numbers.append(item)
return list_of_numbers
def get_bigger_number(list_of_numbers):
bigger_number = max(list_of_numbers)
return bigger_number
def main(list_of_items):
# get list of only numbers
list_of_numbers = get_only_numbers(list_of_items)
# get bigger number
bigger_number = get_bigger_number(list_of_numbers)
print(bigger_number)
Principio de abierto-cerrado
“Las entidades de software… deben estar abiertas a la extensión pero cerradas a la modificación”
esto en resumen dice que lo que ya se tiene desarrollado no es necesario que se rescriba o como mejor lo conocemos refactorizar,simplemente se agregue lo que se necesita ahora, una nueva extension
Mas no significa que ya con esto no se debe modificar el codigo existente cuando las condiciones se necesitan, estoy no es la unica verdad absoluta y como todo en el mundo del desarrollo tiene un “depende”
Tenemos el siguiente ejemplo, que te piden comparar dos numero y obtener el mayor, para eso hacemos la funcion para comparlo, pero que pasa los requerimientos cambian, ahora nos piden calcular el mayor de tres numeros
Ejemplo del comparar dos numeros
def compare_two_numbers(a, b): #2 3 1
if a > b:
return a
return b
Ejemplo refactorizado sin aplicar el principio open-close
def compare_two_or_three_numbers(a, b, c=None):
bigger = b
if a > b:
bigger = a
if c is not None and c > bigger:
bigger = c
return bigger
Ejemplo utilizando este principio
def compare_three_numbers(a, b, c):
more_bigger = compare_two_numbers(compare_two_numbers(a, b), c)
*El principio de sustitución de Liskov*
este principio es de los mas dificiles de entender, nos dice que en algun punto de nuestro codigo estamos creando una clase y creamos clases hijas esa hijas deben poder sustituir a la padre y el codigo siga funcionando de la misma forma
Entre todos los principios SOLID, este es el más abstruso de entender y explicar. Para este principio, no existe una solución estándar "similar a una plantilla" donde deba aplicarse, y es difícil ofrecer un "ejemplo estándar" para mostrar.
*El Principio de Segregación de Interfaz*
“ Muchas interfaces específicas del cliente son mejores que una interfaz de propósito general”
en este principio nos dice que una clase debe tener la interfaz necesaria y evitar metodos que no funcioen o que no tienen que ser parte de esa clase y esto existe ya que avaces se heredan de clases metodos que no se necesitan
Ejemplo de metodo sin sustitucion de liskov, se tiene el problema de que el pinguino es un Ave que hereda de la clase pero en este caso no puede volar
class Bird:
def fly(self):
return 'I can fly!'
def walk(self):
return 'I can walk!'
class Penguin(Bird):
def fly(self):
raise NotImplementedError('Cannot fly')
Ejemplo con el metodo sustitucion de liskov, ahora creamos una nueva clase que hereda de Ave la cual son Aves que si pueden volar
# method liskov substitution principle
class BirdNew:
def walk(self):
return 'I can walk!'
class BirdCanFly(BirdNew):
def fly(self):
return 'I can fly!'
class PenguinNew(BirdNew):
def walk(self):
return super().walk()
class Duck(BirdCanFly):
def fly(self):
return super().fly()
*El Principio de Inversión de Dependencia*
“Las abstracciones no deben depender de los detalles. Los detalles deben depender de la abstracción. Los módulos de alto nivel no deben depender de los módulos de bajo nivel. Ambos deberían depender de abstracciones”
En otras palabras los modulos de alto nivel no deben de depender de odulos de bajo nivel, ambos deben de depender de abstracciones
class Engine(object):
def __init__(self):
pass
def accelerate(self):
pass
def getRPM(self):
currentRPM = 0
#...
return currentRPM
class Vehicle(object):
def __init__(self):
self._engine = Engine()
def getEngineRPM(self):
return self._engine.getRPM()
El código anterior ilustra la manera “habitual” de definir la colaboración entre clases. Como podemos observar, existe una clase Vehicle
que contiene un objeto de la clase Engine
. La clase Vehicle
obtiene las revoluciones del motor invocando el método getEngineRPM
del objeto Motor y devolviendo su resultado. Este caso se corresponde con una dependencia, el módulo superior Vehicle
depende del módulo inferior Engine
, lo cual genera un código tremendamente acoplado y dificil de testear.
Para desacoplar la dependencia Engine
de Vehicle
debemos hacer que la clase Vehicle
deje de responsabilizarse de instanciar el objeto Engine
, inyectándolo como parámetro al constructor, evitando así que la responsabilidad recaiga sobre la propia clase. De este modo desacoplamos ambos objetos, quedando la clase tal que así:
class Vehicle(object):
def __init__(self, engine):
self._engine = engine
def getEngineRPM(self):
return self._engine.getRPM()
if __name__ == '__main__':
vehicle = Vehicle(Engine())
print(vehicle.getEngineRPM())
Top comments (0)