接口继承:你怎么看待这个:

Tru*_*mpi 4 c# oop inheritance liskov-substitution-principle

在查看我们的代码库时,我发现了一个类似于以下模式的继承结构:

interface IBase
{
    void Method1();
    void Method2();
}

interface IInterface2 : IBase
{
    void Method3();
}

class Class1 : IInterface2
{
    ...
}

class Class2 : IInterface2
{
    ...
}

class Class3 : IInterface2
{ 
    ...
}
Run Code Online (Sandbox Code Playgroud)

Class2,Method1投掷NotImplementedException.

问题:

  • 您对继承接口有何看法?
  • 请问之间的关系IBase,并Class2违反了里氏替换原则?

ang*_*son 10

好吧,首先,我一般反对通过抛出NotImplementedException异常来实现接口.它基本上就像是说"嗯,这个类也可以作为一个计算器,错误,差不多".

但在某些情况下,它确实是以"正确的方式"做事的唯一方法,所以我不是100%反对它.

只是需要注意的事情.

接口是合同,通过实现您说您遵守合同的界面.如果你开始否定合同的某些部分,那么对我而言,合同或其实施的结果很难想到.


编辑:在看到Greg Beech的回答之后:如果一个接口专门说实现应该抛出这些异常,那么它是合同的一部分,那么我同意该类完全被允许这样做.


至于替代原则,它指出:

设q(x)是关于类型T的对象x可证明的属性.对于类型S的对象y,q(y)应该为真,其中S是T的子类型.

在这种情况下,如果你改变了方法在后代类型中的作用,它就违反了从基类重写方法的原则.

原则在维基百科页面上更详细,如下面的几点(括号和强调我的评论):

  • 在子类中不能强化前提条件.(前提条件可能是"此类已准备好在此时调用此方法")
  • 后置条件不能在子类中被削弱.(一个后置条件可能是在调用方法之后,关于类的状态是正确的)

由于您没有显示接口的完整契约,只有编译器可以检查的声明部分,因此不可能知道该原则适用于您的实现.

例如,如果您的Method2附加了以下条件:

  • 可以随时调用
  • 修改要为事件链中的下一个事件做好准备的对象的状态

然后抛出NotImplementedException违反了原则.

但是,如果合同还规定:

  • 对于不支持事件链的类,此方法应抛出NotImplementedException或NotSupportedException

然后它可能没有.