简体   繁体   English

Liskov替代原理,前提条件和抽象方法

[英]Liskov substitution principle, preconditions and abstract methods

Liskov substitution principle (LSP) says: Liskov替代原则(LSP)说:

Preconditions cannot be strengthened in a subtype. 前提条件不能在子类型中得到加强。

In C#, I could violate the whole principle as follows: 在C#中,我可能会违反以下总体原则:

public class A 
{
      public virtual void DoStuff(string text)
      {
            Contract.Requires(!string.IsNullOrEmpty(text));
      }
}

public class B : A
{
      public override void DoStuff(string text)
      {
            Contract.Requires(!string.IsNullOrEmpty(text) && text.Length > 10);
      }
}

But, what would happen if A.DoStuff would be an abstract method: 但是,如果A.DoStuffabstract方法,将会发生什么:

public class A 
{
      public abstract void DoStuff(string text);
}

public class B : A
{
      public override void DoStuff(string text)
      {
            Contract.Requires(!string.IsNullOrEmpty(text));
      }
}

Now A.DoStuff is contractless . 现在, A.DoStuff是没有合同的 Or its contract is just everything allowed . 或者它的合同就是所允许的一切

So, is B.DoStuff precondition violating Liskov substitution principle ? 那么, B.DoStuff前提是否违反了Liskov替代原理

It depends on what defines the contract . 这取决于合同的定义

The LSP is a theoretical construct, it does not depend on a specific language or implementation, such as C#'s "Code Contracts" feature. LSP是一种理论构造,它不依赖于特定的语言或实现,例如C#的“代码契约”功能。

The contract can be defined by: 可以通过以下方式定义合同:

  • the method name 方法名称
  • the method parameter names 方法参数名称
  • the method comment 方法注释
  • the return type and the method parameter types 返回类型和方法参数类型
  • "explicit" contracts such as Contract.Requires “明确”合同,例如Contract.Requires

On the last two will be verified by the compiler. 最后两个将由编译器验证。 However, the first three can be part of the contract as well! 但是,前三个也可以成为合同的一部分! Consider the following example: 考虑以下示例:

public interface StuffContainer
{
    void Add(string text);

    // Removes a string that has previously been added.
    void Remove(string text);
}

The name and the documentation of the Remove method define a clear precondition. Remove方法的名称和文档定义了明确的前提条件。 Verifying in an implementation that the string to be removed has previously been added does not violate the LSP. 在实现中验证要删除的字符串先前已添加不会违反LSP。 Verifying that the string has at least 5 characters would violate the LSP. 验证字符串至少包含5个字符将违反LSP。

Yes, you can break the principle very easily, not only in C#. 是的,不仅在C#中,您可以很容易地打破原理。

It only states: 它仅说明:

Subtype Requirement: Let phi(x) be a property provable about objects x of type T. Then phi(y) should be true for objects y of type S where S is a subtype of T. 子类型要求:令phi(x)是关于类型T的对象x可证明的属性。然后,对于类型S的对象y,phi(y)应该为true,其中S是T的子类型。

In your example the type B does not fulfill the property of offering a method DoStuff that works with short texts, despite its supertype A fulfilling it. 在您的示例中,类型B尽管提供了其超类型A,但仍不能提供提供适用于短文本的方法DoStuff的属性。 So the principle is violated. 因此违反了该原则。

It's up to the programmer to uphold the principle. 程序员应坚持这一原则。 A property could also be "it does the right thing", which you could easily break by having a subtype with a wrong implementation of a method. 属性也可以是“做正确的事”,您可以通过使子类型具有错误的方法实现来轻易破坏它。

I'd argue that it's not. 我认为不是。 An abstract method by definition has no preconditions because there is no implementation. 根据定义,抽象方法没有先决条件,因为没有实现。 It would be the same as arguing if implementing an interface breaks LSP. 与实现接口是否中断LSP的争论相同。

Saying A.DoSomething() is contracless is an untrue premise. A.DoSomething()是正确的是不正确的前提。 A.DoSomehing() is undefined, therefore it can not have a contract further than its signature. A.DoSomehing()是未定义的,因此除了其签名之外,它不能具有其他合同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM