C# C"接口实现关系只是";能行;关系
今天有人告诉我,C#中的接口实现只是“可以做”的关系,而不是“is-A”关系。这与我长期以来对LSP(利斯科夫替代原则)的信仰相冲突。我一直认为所有的继承都应该意味着“是一种”关系 所以,如果接口实现只是一种“可以做”的关系。如果有一个接口“IHuman”和“IEngineer”,并且有一个类“Programmer”继承自“IHuman”和“IEngineer”,该怎么办?当然,“程序员”是“IHuman”和“IEngineer”C# C"接口实现关系只是";能行;关系,c#,inheritance,interface,liskov-substitution-principle,C#,Inheritance,Interface,Liskov Substitution Principle,今天有人告诉我,C#中的接口实现只是“可以做”的关系,而不是“is-A”关系。这与我长期以来对LSP(利斯科夫替代原则)的信仰相冲突。我一直认为所有的继承都应该意味着“是一种”关系 所以,如果接口实现只是一种“可以做”的关系。如果有一个接口“IHuman”和“IEngineer”,并且有一个类“Programmer”继承自“IHuman”和“IEngineer”,该怎么办?当然,“程序员”是“IHuman”和“IEngineer” 如果只是“可以做”的关系,这是否意味着我们不能期望“程序员”实例
如果只是“可以做”的关系,这是否意味着我们不能期望“程序员”实例的行为在被视为IHuman和IEngineer时可能有所不同?我倾向于将接口视为行为契约。IComparable和IEnumerable等接口就是典型的例子
在您给出的示例中,IHuman和IEngineer并不是真正的行为 根据我的经验,考虑“是一个”和“可以做”的关系并没有多大帮助。你很快就会遇到问题。基本上,这是现实世界和OO之间的阻抗不匹配。无论人们实际上谈论如何对现实世界建模,您基本上都需要理解类型之间的关系在您使用的平台上意味着什么
有时接口可以用作功能,有时它们更能代表正常的“is-a”关系。我不会对此挂断电话——只要确保您了解他们能做什么和不能做什么。NET framework的设计者使用接口来指定“has a”(或“can do”)关系,而“is a”是使用继承实现的 这方面的基本原理可以在.NET Framework开发者指南的一节中找到: 接口定义了实现者必须提供的一组成员的签名。接口无法提供成员的实现详细信息
因此,由于您的“程序员”和“工程师”示例类很可能具有自己的特定功能,因此它们更适合使用继承来实现。实际上,这就是为什么大多数接口都是功能而不是名称的原因 i可比较,it稳定,i可计算 及 人、动物、狗等 无论如何,正如前面提到的,您必须务实,我在编写代码时有一条一般规则:永远不要让概念、惯例或标准实践妨碍完成工作,最好务实而不是学术。
所以,如果你确信界面确实更适合你的设计,那就去做吧,不要担心像这样的问题。很晚才发现这个问题,但我想插话 C#中的接口具有is-a关系,但不是对象。相反,这是一种实现 换句话说,对于实现IBar的类Foo,以下测试:
Foo myFoo = new Foo();
return myFoo is IBar;
字面上返回true。你也可以说,
IBar bar = myArrayList[3] as IBar;
Foo foo = bar as Foo;
或者,如果一个方法需要一个IBar,您可以传递一个Foo
void DoSomething(IBar bar) {
}
static void Main() {
Foo myFoo = new Foo();
DoSomething(myFoo);
}
显然,IBar本身没有实现,因此can-do关系也适用
interface IBar { void happy(); }
class Foo : IBar
{
void happy()
{
Console.Write("OH MAN I AM SO HAPPY!");
}
}
class Program
{
static void Main()
{
IBar myBar = new Foo();
myBar.happy();
}
}
但是,就这一点而言,对象继承也是如此;继承类Bar的类Foo的对象具有can-do关系以及is-a关系,其方式与接口相同。只是它的实现是为它预先构建的
真正的问题是,你能做什么?继承的类对象是一个-[parent instance],可以执行-[parent's behavior],而接口的实现是一个-[interface implementation],因此可以执行-[interface behavior]
在大多数使用编程is-a关系的情况下(如上面列出的),只对接口进行求值,因此继承的类和实现的接口共享相同的is-a和can-do质量
嗯,,
乔恩:很高兴你喜欢。完成后一定要给我反馈:)如果你有一个只包含抽象方法的抽象类怎么办?这与界面有什么不同?我相信只要有方法就没有区别。那为什么微软带来了两件事呢。继承是有is-a关系的,什么接口实现?@Sudhir.net:我尽量避免谈论“is-a”关系等,正如我在第一句中指出的那样。只有抽象方法的抽象类与接口在许多细节上不同,例如一个类只能从另一个类派生,但能够实现多个接口。类不能声明泛型差异,并且总是值类型(而接口也可以通过值类型实现)。抽象类更容易进化,因为可以添加新的(非抽象)方法,而不破坏现有的子类。@Jon,我的抽象类在整个应用程序周期中只有一个abtract。将来abtract类没有变化,例如没有多个接口,没有字段,没有非abtract方法。那我的界面有什么不同呢。?我想从实现的角度来理解,微软的想法是什么?@Sudhir.net:这并不是说C#是第一个进行这种拆分的语言——首先,它与Java中的抽象类和接口非常相似。问题不在于抽象类实现了多个接口,而是如果您有第二个抽象类,则单个类无法从这两个抽象类派生,但它可以实现多个接口。真的,所以评论并不是讨论这些差异的最佳场所——我建议你找一本好的入门C#书。