Понимание принципа подстановки Лискова

Мой пример программы, как показано ниже;

    public class Animal
    {
        public virtual string MakeSound()
        {
            return "General Sound";
        }
    }

    public class Dog : Animal
    {
        public override string MakeSound()
        {
            return "Bow..Bow..";
        }
    }
}

        static void Main(string[] args)
        {
            Animal obj1 = new Animal();
            Console.WriteLine("General Animal's sound id " + obj1.MakeSound());

            Dog obj2 = new Dog();
            Console.WriteLine("Dog Animal's sound id " + obj2.MakeSound());

            //Violate LSP
            Animal obj3 = new Dog();
            Console.WriteLine("Animal's sound id " + obj3.MakeSound());

            Console.ReadKey();
        }

Здесь, насколько я понимаю, когда мы создаем экземпляр Dog для Animal, такой как obj3, мы нарушаем LSP. Пожалуйста, подтвердите мое понимание. Если да, скажите, пожалуйста, как добиться в этом случае лучшего понимания. Я думаю, что мое кодирование является концептуально правильным

2 ответа

Ваш пример на самом деле не нарушает LSP. Я думаю, что лучшим примером нарушения будет что-то вроде

public class Bird
{     
    public virtual void Fly(int height);   
}

public class Penguin : Bird
{
    public virtual void Swim(int depth);
}

public static class BirdExtensions
{
    public static void Fly(this Bird bird)
    {
    }
}

Если я передам экземпляр Penguin этому методу, мне, возможно, придется сгенерировать исключение во время выполнения или что-то еще, потому что мой Penguin не может летать:(

Вы видите, что мы сделали предположение о базовом классе (все птицы могут летать), но теперь у нас есть пример дочернего класса, который не соответствует этому предположению (пингвины не могут летать).

Кроме того, потому что Penguin это Bird, у него есть метод для Fly(height=10)так что я мог бы технически сделать что-то вроде,

Bird b = new Penguin();
b.Fly(height=100);
b.Swim(depth=20);

Что нарушает возможности Пингвина (он не может летать так высоко, он может летать только в 0, может быть...?).

Вы не нарушаете правила замещения Лискова.

Правило замены Лискова на простом английском -> если Base.Method оставляет какие-то инварианты, то Derived.Method должны поддерживать эти инварианты.

инвариант - это состояние объекта, которое не изменяется в результате выполнения метода.

например:

public class MyInt{
   private int num1 = 5;

   public void print(){
      Console.write(num1);
   }    

   public void increment(){
     num1++;
   }

} 

здесь инварианты print только num1потому что это не изменилось. инварианты increment не, потому что это меняет все MyInt члены.

В вашем примере:

инвариант, который Animal.MakeSound имеет: не
инвариант, который Dog.MakeSound имеет: не

инварианты Animal.MakeSound поддерживаются в Dog.MakeSoundТаким образом, правило подмены Лискова не нарушено.

Другие вопросы по тегам