Chciałbym odnieść się do przykładu, który był używany wcześniej na SO z Duck and Electric Duck:C# jest interfejs zarzucali naruszenie zasada podstawienia 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; }
}
Oryginalny naruszenie przez LSP będzie wyglądać tak:
void MakeDuckSwim(IDuck duck)
{
if (duck is ElectricDuck)
((ElectricDuck)duck).TurnOn();
duck.Swim();
}
Jednym z rozwiązań przez autora było umieścić wewnątrz metody Logic pływać kaczka elektrycznego, aby włączyć się na:
public class ElectricDuck : IDuck
{
public void Swim()
{
if (!IsTurnedOn)
TurnOn();
//swim logic
}
public void TurnOn()
{
this.IsTurnedOn = true;
}
public bool IsTurnedOn { get; set; }
}
mam natknąć innych scenariuszy, gdzie rozszerzony interfejs może być utworzone, który obsługuje jakiś inicjalizacji:
public interface IInitializeRequired
{
public void Init();
}
elektryczny Duck może następnie zostać przedłużony z tego interfejsu:
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
}
EDIT : Powód rozszerzonego interfejsu Opiera się na twierdzeniu autora, że automatyczne włączanie metody pływania może mieć inne niepożądane wyniki.
Następnie metoda zamiast sprawdzania i rzucając się do określonego rodzaju może patrzeć przez dłuższy interfejsu Zamiast:
void MakeDuckSwim2(IDuck duck)
{
var init = duck as IInitializeRequired;
if (init != null)
{
init.Init();
}
duck.Swim();
}
Fakt, że zrobiłem koncepcję inicjowania bardziej abstrakcyjne następnie stworzyć rozszerzony interfejs o nazwie IElectricDuck z Metoda TurnOn() może sprawiać wrażenie, że postąpiłem słusznie, jednak cała koncepcja Init może istnieć tylko z powodu elektrycznej kaczki.
Czy jest to lepszy sposób/rozwiązanie, czy jest to tylko naruszenie LSP w przebraniu.
Dzięki
Dlaczego nie tylko zmniejszyć problem z kolejnym uogólnieniem? Krótko mówiąc na przykład: "IDuck.HasEnergy" itp., Możesz wymusić "uzyskanie energii", która będzie taka sama w zasadzie dla każdej kaczki, ale różni się w szczegółach (można jeść, inne wkładane baterie lub włączyć). –
Zastanawiałem się nad tymi kwestiami, jednak pozostaje pytanie, czy metoda nie bierze argumentów za tymi interfejsami, ale raczej na najwyższym poziomie, a następnie odlewania interfejsu, może to spowodować takie same problemy z naruszeniem LSP, gdy dodawane są inne uogólnienia, na przykład CanGetEnergy() teraz nagle wszystkie metody będą musiały dodać tę logikę. – Andre
Na czym polega problem polegający na tym, aby logika wewnątrz metody pływania elektrycznego kaczki mogła się włączyć? –