¿Puede explicar el principio de sustitución de Liskov (la 'L' de SOLID) con un buen ejemplo de C # que cubra todos los aspectos del principio de una manera simplificada? Si es realmente posible.
c#
.net
oop
solid-principles
liskov-substitution-principle
pastel de lápiz
fuente
fuente
Respuestas:
(Esta respuesta ha sido reescrita 2013-05-13, lea la discusión en la parte inferior de los comentarios)
LSP se trata de seguir el contrato de la clase base.
Por ejemplo, no puede lanzar nuevas excepciones en las subclases, ya que el que usa la clase base no lo esperaría. Lo mismo ocurre si la clase base arroja
ArgumentNullException
si falta un argumento y la subclase permite que el argumento sea nulo, también una violación de LSP.Aquí hay un ejemplo de una estructura de clase que viola LSP:
Y el código de llamada
Como puede ver, hay dos ejemplos de patos. Un pato orgánico y un pato eléctrico. El pato eléctrico solo puede nadar si está encendido. Esto rompe el principio LSP, ya que debe estar encendido para poder nadar ya que
IsSwimming
que (que también es parte del contrato) no se establecerá como en la clase base.Por supuesto, puede resolverlo haciendo algo como esto
Pero eso rompería el principio Abierto / Cerrado y tiene que implementarse en todas partes (y por lo tanto aún genera código inestable).
La solución adecuada sería encender automáticamente el pato en el
Swim
método y, al hacerlo, hacer que el pato eléctrico se comporte exactamente como lo define laIDuck
interfaz.Actualizar
Alguien agregó un comentario y lo eliminó. Tenía un punto válido que me gustaría abordar:
La solución con encender el pato dentro del
Swim
método puede tener efectos secundarios cuando se trabaja con la implementación real (ElectricDuck
). Pero eso se puede resolver utilizando una implementación de interfaz explícita . En mi humilde opinión, es más probable que tenga problemas al NO encenderlo,Swim
ya que se espera que nade al usar laIDuck
interfazActualización 2
Reformulé algunas partes para que quede más claro.
fuente
if duck is ElectricDuck
parte. Tuve un seminario sobre SOLID el jueves pasado :)as
palabra clave, lo que en realidad los salva de una gran cantidad de verificación de tipos. Estoy pensando en algo como lo siguiente:if var electricDuck = duck as ElectricDuck; if(electricDuck != null) electricDuck.TurnOn();
if S is a subtype of T, then objects of type T in a program may be replaced with objects of type S without altering any of the desirable properties of that program (e.g., correctness).
LSP un enfoque práctico
Dondequiera que busque ejemplos de C # de LSP, la gente ha usado clases e interfaces imaginarias. Aquí está la implementación práctica de LSP que implementé en uno de nuestros sistemas.
Escenario: Supongamos que tenemos 3 bases de datos (Clientes hipotecarios, Clientes de cuentas corrientes y Clientes de cuentas de ahorro) que proporcionan datos del cliente y necesitamos detalles del cliente para el apellido del cliente dado. Ahora podemos obtener más de 1 detalle de cliente de esas 3 bases de datos con el apellido dado.
Implementación:
CAPA DEL MODELO DE NEGOCIO:
CAPA DE ACCESO A DATOS:
La interfaz anterior es implementada por la clase abstracta
Esta clase abstracta tiene un método común "GetDetails" para las 3 bases de datos que se extiende por cada una de las clases de base de datos como se muestra a continuación
ACCESO A DATOS DEL CLIENTE HIPOTECARIO:
ACCESO A LOS DATOS DEL CLIENTE DE LA CUENTA ACTUAL:
CUENTA DE AHORROS ACCESO A DATOS DEL CLIENTE:
Una vez establecidas estas 3 clases de acceso a datos, ahora llamamos nuestra atención al cliente. En la capa Business tenemos la clase CustomerServiceManager que devuelve los detalles del cliente a sus clientes.
CAPA DE NEGOCIOS:
No he mostrado la inyección de dependencia para que sea simple, ya que ahora se está complicando.
Ahora, si tenemos una nueva base de datos de detalles de clientes, podemos agregar una nueva clase que amplíe BaseDataAccess y proporcione su objeto de base de datos.
Por supuesto, necesitamos procedimientos almacenados idénticos en todas las bases de datos participantes.
Por último, el cliente de la
CustomerServiceManager
clase solo llamará al método GetCustomerDetails, pasará el apellido y no debería preocuparse por cómo y de dónde provienen los datos.Espero que esto le brinde un enfoque práctico para comprender LSP.
fuente
Aquí está el código para aplicar el principio de sustitución de Liskov.
LSV establece: "Las clases derivadas deben ser sustituibles por sus clases base (o interfaces)" & "Los métodos que usan referencias a clases base (o interfaces) deben poder usar métodos de las clases derivadas sin saberlo ni conocer los detalles . "
fuente