Principio de sustitución de Liskov

Buenas prácticas, Desarrollo

Liskov Substitution – SOLID III

14 Oct , 2014  

Liskov Substitution, las clases hijas pueden usarse como los padres sin conocer las diferencias entre ellas

Este principio, desarrollado principalmente por Barbara Liskov, reza lo siguiente:

Debe ser posible utilizar cualquier objeto instancia de una subclase en lugar de cualquier objeto instancia de su superclase sin que la semántica del programa escrito en los términos de la superclase se vea afectado

Fácil, ¿verdad?. Bueno, creo que será mucho más sencillo explicarlo con un ejemplo. Casi todos los ejemplos referentes a Liskov Substitution se centran en un rectángulo y un cuadrado. Probemos algo diferente.

De aves va la cosa…

Supongamos que tenemos una super clase Pájaro, con sus métodos de comer y volar. Por otra parte tenemos un par de clases más, Pingüino y Cuervo, siendo ambas hijas de nuestra clase pájaro:

class Bird
 def eat
   puts "¡Wow, estoy comiendo!"
 end

 def fly
   puts "¡Wow, estoy volando!"
 end
end

class Crow < Bird
 def initialize(color = "black")
   @color = color
   puts "Hola, soy un cuervo de color #{@color}"
 end
end


class Penguin < Bird
 def initialize(color = "black")
   @color = color
   puts "Hola, soy un pingüino de color #{@color}"
 end

 def fly
   raise "No puedo volar, snifff"
 end
end

Liskov Substitution sostiene que si conocemos como funciona la clase Pájaro y sus métodos debemos esperar que tanto Pingüino como Cuervo se comporten de la misma forma. Por tanto, alguien que vaya a trabajar con estas clases podrá crear sendos objetos Pingüino y Cuervo y pretender que coman y vuelen:

my_bird = Crow.new
puts my_bird.eat
puts my_bird.fly

other_bird = Penguin.new
puts other_bird.eat
puts other_bird.fly # Y nos encontramos con un error

Cuando esperamos encontrar un bonito vuelo de nuestro pingüino nos encontramos con un error similar al siguiente:

irb(main):124:0> puts other_bird.fly
RuntimeError: No puedo volar, snifff
from (irb):114:in `fly'
from (irb):124
from ~/.rbenv/versions/2.1.3/bin/irb:11:in `<main>'

¿Qué es lo que ha pasado?

La respuesta es simple: un pingüino no es un pájaro. No, no me he vuelto loco. En este contexto un pingüino es una porción de código, o lo que es lo mismo, una representación imaginaria de algo real. Si tenemos en cuenta esto podemos comprender que las relaciones de la vida real pueden no servirnos al realizar sus representaciones programadas. Citando a Bob Martin la explicación más sencilla para entender esto es la siguiente:

Imaginemos que dos personas quieren divorciarse. Cada una de ellas contratará a un abogado que se hará cargo de su representación. Es muy poco probable que esos dos abogados también se estén divorciando porque las representaciones de las cosas no comparte las relaciones de las cosas que representan.

El Duck Typing

Como acostumbro a hacer, el ejemplo anteriormente realizado está escrito en Ruby, algo que hace que este principio pueda ser algo diferente en otros lenguajes orientados a objetos. Ruby es un lenguaje dinámico, lo que implica que hace uso del Duck Typing, un concepto que explicaré en otro artículo ampliamente pero que, en resumidas cuentas, quiere decir que la validez semántica de nuestro código viene definía por los métodos y propiedades que se utilizan en el mismo, y no por la herencia de clases o interfaces del mismo, como ocurriría en otros lenguajes (por ejemplo Java).

Cuando veo un ave que camina como un pato, nada como un pato y suena como un pato, a esa ave yo la llamo pato

El problema del Duck Typing y este principio es que podemos estar cometiendo una violación del mismo pero nuestro código será semánticamente correcto. Por tanto debemos fijarnos más en las respuestas que el código nos devuelve, para comprobar que sea lo que cabría esperar.

En nuestro ejemplo tenemos un pingüino que caminaba como un pingüino, comía como un pingüino, pero pretendía volar, ya que su clase padre permite volar. Para evitar que volara tuvimos que preparar una excepción que se lo impidiera, y esto es una clara violación del principio.

Más información

, , ,

By  -        
Soy un Full Stack Developer que vive en Valladolid. Actualmente trabajo en la empresa Ilunion Tecnología y Accesibilidad. Soy un apasionado de la informática, la tecnología, aficionado a la fotografía y enamorado del diseño eficiente.



Deja un comentario