什么时候使用接口或抽象类?什么时候用? [英] When to use interfaces or abstract classes? When to use both?

查看:31
本文介绍了什么时候使用接口或抽象类?什么时候用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

虽然某些指导方针规定,当您想为继承不明确的类(IDomesticated)和继承是另一个类的扩展(Cat : Mammal, Snake : Reptile),在某些情况下(在我看来)这些指南进入了灰色区域.

While certain guidelines state that you should use an interface when you want to define a contract for a class where inheritance is not clear (IDomesticated) and inheritance when the class is an extension of another (Cat : Mammal, Snake : Reptile), there are cases when (in my opinion) these guidelines enter a gray area.

例如,假设我的实现是 Cat : Pet.Pet 是一个抽象类.是否应该扩展为 Cat : Mammal, IDomesticated 其中 Mammal 是一个抽象类而 IDomesticated 是一个接口?还是我与 KISS/YAGNI 原则(尽管我不确定将来是否会出现 Wolf 类,这不会可以从Pet继承)?

For example, say my implementation was Cat : Pet. Pet is an abstract class. Should that be expanded to Cat : Mammal, IDomesticated where Mammal is an abstract class and IDomesticated is an interface? Or am I in conflict with the KISS/YAGNI principles (even though I'm not sure whether there will be a Wolf class in the future, which would not be able to inherit from Pet)?

远离隐喻的Cats 和Pets,假设我有一些类代表传入数据的来源.他们都需要以某种方式实现相同的基础.我可以在抽象的 Source 类中实现一些通用代码并从中继承.我也可以制作一个 ISource 接口(对我来说感觉更正确")并在每个类中重新实现通用代码(这不太直观).最后,我可以通过创建抽象类和接口来吃蛋糕".什么是最好的?

Moving away from the metaphorical Cats and Pets, let's say I have some classes that represent sources for incoming data. They all need to implement the same base somehow. I could implement some generic code in an abstract Source class and inherit from it. I could also just make an ISource interface (which feels more "right" to me) and re-implement the generic code in each class (which is less intuitive). Finally, I could "have the cake and eat it" by making both the abstract class and the interface. What's best?

这两种情况提出了仅使用抽象类,仅使用接口以及同时使用抽象类和接口的要点.这些都是有效的选择,还是有什么规则"可以用来代替另一个?

These two cases bring up points for using only an abstract class, only an interface and using both an abstract class and an interface. Are these all valid choices, or are there "rules" for when one should be used over another?

我想通过同时使用抽象类和接口"来澄清这一点,其中包括它们本质上表示相同事物的情况(SourceISource两者都具有相同的成员),但该类添加了通用功能,而接口指定了协定.

I'd like to clarify that by "using both an abstract class and an interface" that includes the case when they essentially represent the same thing (Source and ISource both have the same members), but the class adds generic functionality while the interface specifies the contract.

另外值得注意的是,这个问题主要针对不支持多重继承的语言(如.NET和Java).

Also worth noting is that this question is mostly for languages that do not support multiple inheritance (such as .NET and Java).

推荐答案

作为第一条经验法则,我更喜欢抽象类而不是接口,基于 .NET 设计指南.推理的适用范围比 .NET 广泛得多,但在 框架设计指南.

As a first rule of thumb, I prefer abstract classes over interfaces, based on the .NET Design Guidelines. The reasoning applies much wider than .NET, but is better explained in the book Framework Design Guidelines.

偏爱抽象基类的主要原因是版本控制,因为您总是可以在不破坏现有客户端的情况下向抽象基类添加新的虚拟成员.这在接口上是不可能的.

The main reasoning behind the preference for abstract base classes is versioning, because you can always add a new virtual member to an abstract base class without breaking existing clients. That's not possible with interfaces.

在某些情况下,接口仍然是正确的选择(尤其是当您不关心版本控制时),但了解其优缺点可以让您做出正确的决定.

There are scenarios where an interface is still the correct choice (particularly when you don't care about versioning), but being aware of the advantages and disadvantages enables you to make the correct decision.

所以作为我继续之前的部分答案:只有当您决定首先针对接口进行编码时,同时拥有接口和基类才有意义.如果您允许某个接口,则必须仅针对该接口进行编码,否则将违反 Liskov 替换原则.换句话说,即使您提供了实现该接口的基类,也不能让您的代码使用该基类.

So as a partial answer before I continue: Having both an interface and a base class only makes sense if you decide to code against an interface in the first place. If you allow an interface, you must code against that interface only, since otherwise you would be violating the Liskov Substitution Principle. In other words, even if you provide a base class that implements the interface, you cannot let your code consume that base class.

如果您决定针对基类进行编码,那么拥有接口就毫无意义.

If you decide to code against a base class, having an interface makes no sense.

如果您决定针对接口进行编码,则可以选择提供提供默认功能的基类.这不是必需的,但可能会加快实施者的速度,因此您可以提供一个作为礼貌.

If you decide to code against an interface, having a base class that provides default functionality is optional. It is not necessary, but may speed up things for implementers, so you can provide one as a courtesy.

我想到的一个例子是 ASP.NET MVC.请求管道适用于 IController,但有一个 Controller 基类,您通常会使用它来实现行为.

An example that springs to mind is in ASP.NET MVC. The request pipeline works on IController, but there's a Controller base class that you typically use to implement behavior.

最终答案:如果使用抽象基类,请仅使用它.如果使用接口,则基类对于实现者来说是可选的.

Final answer: If using an abstract base class, use only that. If using an interface, a base class is an optional courtesy to implementers.

更新:不再更喜欢抽象类而不是接口,而且我已经很久没有了;相反,我更喜欢组合而不是继承,使用 SOLID 作为指导.

Update: I no longer prefer abstract classes over interfaces, and I haven't for a long time; instead, I favour composition over inheritance, using SOLID as a guideline.

(虽然我可以直接编辑上面的文本,但它会从根本上改变帖子的性质,而且由于一些人发现它足够有价值,所以我宁愿保留原文,并且改为添加此注释.帖子的后半部分仍然有意义,因此删除它也是一种耻辱.)

(While I could edit the above text directly, it would radically change the nature of the post, and since a few people have found it valuable enough to up-vote it, I'd rather let the original text stand, and instead add this note. The latter part of the post is still meaningful, so it would be a shame to delete it, too.)

这篇关于什么时候使用接口或抽象类?什么时候用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆