了解Liskov替代原则

时间:2016-04-26 16:53:01

标签: c# design-patterns liskov-substitution-principle

我的示例程序如下;

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

这里作为我的理解当我们像obj3一样为Animal创建Dog实例时,我们违反了LSP。请证实我的理解。如果是,请告诉我如何在这种情况下实现更好地理解。我认为我的编码在概念上是正确的

2 个答案:

答案 0 :(得分:0)

你没有违反Liskov的替代规则。

Liskov轻松英语中的替换规则 - >如果Base.Method留下任何不变量,那么Derived.Method必须知道这些不变量。

invariant是一个对象的状态,它不会因方法执行而改变。

例如:

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的不变量,因此Liskov替换规则不会被破坏。

答案 1 :(得分:0)

您的示例并未真正违反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是一个Bird,它有Fly(height=10)的方法,所以我在技术上可以做类似的事情,

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

这违反了企鹅的能力(他不能飞得那么高,他只能飞到0,也许......?)。