Closed. This question needs to be more focused。它当前不接受答案。












想改善这个问题吗?更新问题,使其仅关注editing this post的一个问题。

1年前关闭。



Improve this question




您能用一个很好的C#示例以简单的方式解释Liskov替代原理(SOLID的“L”)吗?如果真的有可能。

最佳答案

(此答案已被改写为2013-05-13,请阅读评论底部的讨论)

LSP是关于遵循基类的契约(Contract)的。

例如,您不能在子类中引发新的异常,因为使用基类的异常不会发生这种情况。如果基类在缺少参数时抛出ArgumentNullException,并且子类允许参数为null(同样违反LSP),则也是如此。

这是违反LSP的类结构的示例:

public interface IDuck
{
   void Swim();
   // contract says that IsSwimming should be true if Swim has been called.
   bool IsSwimming { get; }
}

public class OrganicDuck : IDuck
{
   public void Swim()
   {
      //do something to swim
   }

   bool IsSwimming { get { /* return if the duck is swimming */ } }
}

public class ElectricDuck : IDuck
{
   bool _isSwimming;

   public void Swim()
   {
      if (!IsTurnedOn)
        return;

      _isSwimming = true;
      //swim logic
   }

   bool IsSwimming { get { return _isSwimming; } }
}

和调用代码
void MakeDuckSwim(IDuck duck)
{
    duck.Swim();
}

如您所见,有两个鸭子的例子。一只有机鸭和一只电鸭。电动鸭子只有在打开的情况下才能游泳。这违反了LSP原理,因为必须将其打开才能游泳,因为IsSwimming(也是契约(Contract)的一部分)不会像在基类中那样设置。

您当然可以通过执行以下操作来解决它
void MakeDuckSwim(IDuck duck)
{
    if (duck is ElectricDuck)
        ((ElectricDuck)duck).TurnOn();
    duck.Swim();
}

但这会破坏“打开/关闭”原理,必须在任何地方实现(因此仍然会生成不稳定的代码)。

正确的解决方案是使用Swim方法自动打开鸭子,并通过这种方式使电动鸭子的行为与IDuck接口(interface)定义的完全相同

更新

有人添加了评论并将其删除。我想谈谈一个有效的观点:

在使用实际实现(Swim)时,在ElectricDuck方法内部打开鸭子的解决方案可能会有副作用。但这可以通过使用explicit interface implementation来解决。恕我直言,您更有可能通过在Swim中不打开它来遇到问题,因为预期在使用IDuck接口(interface)时它将游动

更新2

改写一些部分以使其更清晰。

09-07 06:36