Интерфейс C # нарушает принцип подстановки Лискова.

Я хотел бы сослаться на пример, который использовался ранее на SO с уткой и электрической уткой:

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; }
}

Первоначальное нарушение LSP могло бы выглядеть так:

 void MakeDuckSwim(IDuck duck)
    {
        if (duck is ElectricDuck)
            ((ElectricDuck)duck).TurnOn();
        duck.Swim();
    }

Одно из решений автора заключалось в том, чтобы поместить логику в метод плавания электрической утки, чтобы она включалась:

public class ElectricDuck : IDuck
{
    public void Swim()
    {
        if (!IsTurnedOn)
            TurnOn();

        //swim logic  
    }

    public void TurnOn()
    {
        this.IsTurnedOn = true;
    }

    public bool IsTurnedOn { get; set; }
}

Я пришел в других сценариях, где может быть создан расширенный интерфейс, поддерживающий какую-либо инициализацию:

public interface IInitializeRequired
{
    public void Init();
}

Electric Duck затем может быть расширен с помощью этого интерфейса:

 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
}

РЕДАКТИРОВАТЬ: Причина расширенного интерфейса основана на утверждении автора, что включение автоматически в методе плавания могут иметь другие нежелательные результаты.

Тогда метод вместо проверки и преобразования к определенному типу может вместо этого искать расширенный интерфейс:

void MakeDuckSwim2(IDuck duck)
    {
        var init = duck as IInitializeRequired;
        if (init != null)
        {
            init.Init();
        }

        duck.Swim();
    }

Тот факт, что я сделал концепцию инициализации более абстрактной, чем для создания расширенного интерфейса под названием IElectricDuck с методом TurnOn (), Может показаться, что я поступил правильно, однако вся концепция Init может существовать только из-за электрического утка.

Это лучший способ / решение или это просто замаскированное нарушение LSP.

Спасибо

6
задан Community 23 May 2017 в 11:46
поделиться