me gustaría hacer referencia al ejemplo que se utilizó antes de SO con el pato y el pato eléctrica:C# es la interfaz que echa una violación del principio de sustitución de liskov
public interface IDuck
{
void Swim();
}
public class Duck : IDuck
{
public void Swim()
{
//do something to swim
}
}
public class ElectricDuck : IDuck
{
public void Swim()
{
if (!IsTurnedOn)
return;
//swim logic
}
public void TurnOn()
{
this.IsTurnedOn = true;
}
public bool IsTurnedOn { get; set; }
}
La violación original para LSP se vería de esta manera:
void MakeDuckSwim(IDuck duck)
{
if (duck is ElectricDuck)
((ElectricDuck)duck).TurnOn();
duck.Swim();
}
Una solución por el autor fue poner la lógica dentro método de natación del pato eléctrica para que se encienda:
public class ElectricDuck : IDuck
{
public void Swim()
{
if (!IsTurnedOn)
TurnOn();
//swim logic
}
public void TurnOn()
{
this.IsTurnedOn = true;
}
public bool IsTurnedOn { get; set; }
}
me he encontrado con otros escenarios donde una interfaz extendida puede ser creado que admite algún tipo de inicialización:
public interface IInitializeRequired
{
public void Init();
}
pato eléctrico podría ampliarse con esta interfaz:
public class ElectricDuck : IDuck, IInitializeRequired
{
public void Swim()
{
if (!IsTurnedOn)
return;
//swim logic
}
public void TurnOn()
{
this.IsTurnedOn = true;
}
public bool IsTurnedOn { get; set; }
#region IInitializeRequired Members
public void Init()
{
TurnOn();
}
#endregion
}
EDITAR : El motivo de la interfaz extendida se basa en que el autor dice que encenderse automáticamente en el método de nado podría tener otros resultados no deseados.
A continuación, el método en vez de comprobar y echando a un tipo específico puede buscar una interfaz extendida en su lugar:
void MakeDuckSwim2(IDuck duck)
{
var init = duck as IInitializeRequired;
if (init != null)
{
init.Init();
}
duck.Swim();
}
El hecho de que hice el concepto de inicialización más abstracto a continuación para crear una interfaz extendida llamada IElectricDuck con El método TurnOn(), puede hacer que parezca que hice lo correcto, sin embargo, todo el concepto Init puede existir solo debido a un pato eléctrico.
¿Es esta una mejor forma/solución o es solo una violación de LSP disfrazada?
Gracias
¿Por qué no reducir aún más el problema con otra generalización? Brevemente, por ejemplo: 'IDuck.HasEnergy', etc., puede aplicar 'obtener energía', que será el mismo en principio para cada pato, pero diferente en detalles (uno podría comer, el otro insertar baterías o encenderse). –
Estaba pensando en estas líneas, pero queda la pregunta de que el método no toma un argumento para estas interfaces, sino más bien en el nivel más alto y luego realiza fundición de interfaz, esto podría causar los mismos problemas de violación LSP cuando se agregan otras generalizaciones, por ejemplo, CanGetEnergy() de repente ahora todos los métodos necesitarían agregar esta lógica – Andre
¿Cuál es el problema para poner la lógica dentro del método de nado eléctrico del pato para encenderse? –