什么时候需要接口?

发布于 2024-07-14 03:17:13 字数 739 浏览 5 评论 0 原文

(在 .NET 的上下文中,无论其价值如何)

我倾向于不使用继承,也很少使用接口。 我遇到过一个人,他认为接口是自吐口水以来最好的东西。 他到处都使用它们。 我不明白这一点,因此不明白接下来的问题。 我只是想检查一下我对接口的理解。

如果您在任何地方都使用界面,我假设您可以预测未来,您的应用程序要求已确定,并且您的应用程序中不会发生任何变化。 对我来说,尤其是在早期开发过程中,界面成为一种阻力。 该应用程序在其生命周期中非常动态。 如果您需要在接口中减去或添加成员,很多东西都会被破坏。 上面的人说他创建了另一个界面来处理新成员。 没有任何损坏。

这不是组合吗? 为什么不使用没有接口的组合呢? 更灵活。

他如何处理必须从接口中减去成员的情况? 基本上他没有。 事情就这样发生了,这很棒,因为现在您可以看到所有受影响的区域并修复它们。 我们不应该更优雅地找出所有相关代码路径在哪里,而是应该通过暴力破解部分类?

我将软件应用程序视为图表。 完整图是最坏的情况,有 n(n-1)/2。 这意味着每个班级都与每个班级交谈。 令人困惑的蜘蛛网。 n-1 是最好的,其中他们是严格的通信层次结构。 添加另一个接口只是为了补偿新需要的成员,从而在图中添加一个顶点,这意味着更多的边和更强的 n(n-1)/2 方程实现。 没有接口的组合更像是 mixin。 只有选定的类才使用特定的方法。 通过接口,所有类都被迫使用成员,即使它们不需要它们。 组合/混合方法不会添加新的不需要的边缘。

(In the context of .NET for what its worth)

I tend to not use inheritance and rarely use interfaces. I came across someone who thinks interfaces are the best thing since spit. He uses them everywhere. I don't understand this and hence the questions that follow. I just want a check on my understanding of interfaces.

If you are using interfaces everywhere, I'm assuming you can predict the future, your app requirements are nailed down and nothing will ever change in your app. For me, during early development especially, interfaces become a drag. The app is very dynamic through its life. If you need to subtract or add members to the interface, lots of stuff will break. The guy above says he creates another interface to handle the new member(s). Nothing breaks.

Isn't that composition? Why not use composition without interfaces? More flexible.

How does he handle the case where a member must be subtracted from the interface? Basically he doesn't. Things just break and that is great because now you can see all of the affected areas and fix them. Instead of figuring out more elegantly where all of the related code paths are, we should just rip out parts of classes through brute force?

I think of a software application as a graph. A complete graph is the worst case, having n(n-1)/2. This means every class talks to every class. A confusing spider web. n-1 is the best, in which their is a strict hierarchy of communication. Adding another interface just to compensate for a new needed member adds a vertici to the graph, which means more edges and a stronger realization of the n(n-1)/2 equation. Composition without interfaces is more like mixins. Only select classes use particular methods. With an interface, all classes are forced to use members, even if they don't need them. The composition/mixin approach doesn't add new unneeded edges.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(15

萝莉病 2024-07-21 03:17:13

接口不会强制类使用方法。 他们强制实现类实现所有方法,但这是另一回事。

我喜欢接口将 API 与实现分开的方式。 诚然,这也是通过访问修饰符完成的,但接口使其更加清晰。 更重要的是,接口还使模拟变得更容易——这意味着您甚至可以在实现依赖于接口的类之前对其进行单元测试。

是的,这意味着我经常会得到一个只有一个生产实现的界面。 在我看来这不是问题,因为我已经获得了可测试性。

另一方面,我不会为每个类编写接口。 我喜欢编写接口,其中对象本质上提供服务 - 身份验证、数据访问等。普通数据对象(即使具有重要的行为)在接口、IME 方面没有那么有用。

Interfaces don't force classes to use methods. They force implementing classes to implement all methods, but that's a different matter.

I like the way that interfaces separate out API from implementation. Admittedly this is also done with access modifiers, but interfaces make it clearer. More importantly, interfaces also make mocking easier - which means that you can unit test the classes which depend on the interface even before you've ever implemented it.

And yes, this means I often end up with an interface which only has a single production implementation. That isn't a problem in my view, because I've gained testability.

On the other hand, I don't write an interface for every class. I like to write interfaces where an object is essentially providing a service - authentication, data access etc. Plain data objects (even with significant behaviour) aren't as useful in terms of interfaces, IME.

落花随流水 2024-07-21 03:17:13

根据 wikipedia

多态性在工业中的主要用途(面向对象编程理论)是属于不同类型的对象响应同名的方法、字段或属性调用的能力,每个调用都根据适当的特定于类型的行为。 程序员(和程序)不必提前知道对象的确切类型,因此确切的行为是在运行时确定的(这称为后期绑定或动态绑定)。

这就是接口的原因太有用了。

“上面的人说他创建了另一个接口来处理新成员。没有任何问题。”

我只是在这里猜测,但听起来这个人来自老派 COM 背景(当然,我可能是错的!)。 让我想起我所编写的所有代码,其中我看到过这样的事情:

  • IWidgetManager
  • IWidgetManager2
  • IWidgetManager3

这不是使用界面的好方法。 根据我的经验,我见过两个极端:害怕改变界面以至于每当添加新成员时都会创建新界面,或者根本不使用界面并且拥有一个遭受高度耦合。 你需要找到一个良好的平衡点。 改变界面并不总是世界末日。

您正在进行的项目有多大? 如果项目规模相对较小,则很难看出接口的好处。 另一方面,如果这是一个具有数十万行代码并且由许多模块组成的项目,那么好处就变得更加明显。

According to wikipedia,

The primary usage of polymorphism in industry (object-oriented programming theory) is the ability of objects belonging to different types to respond to method, field, or property calls of the same name, each one according to an appropriate type-specific behavior. The programmer (and the program) does not have to know the exact type of the object in advance, and so the exact behavior is determined at run time (this is called late binding or dynamic binding).

That's what makes interfaces so useful.

"The guy above says he creates another interface to handle the new member(s). Nothing breaks."

I'm just guessing here, but it sounds like this guy comes from an old school COM background (I could be wrong, of course!). Makes me cringe to think of all of the code I've worked on where I've seen things like this:

  • IWidgetManager
  • IWidgetManager2
  • IWidgetManager3

That's not a good way to work with interfaces. In my experience, I've seen both extremes: fear of changing interfaces to the point where new interfaces are created whenever new members are added, or not using interfaces at all and having a product that suffers from a high degree of coupling. You need to find a good balance. It isn't always the end of the world to change an interface.

What is the size of the project you're working on? It can be hard to see the benefit of interfaces if it is a relatively small size project. If, on the other hand, it's a project with several hundred thousand lines of code and is composed of many modules, the benefits become far more apparent.

一曲爱恨情仇 2024-07-21 03:17:13

接口有很多有用的情况。 当您需要向一个类添加可以在各种类中找到的特定行为时,这就是使用接口的最佳时机。 一个很好的例子是 IDisposable 接口 - 您有一些资源,当您完成后,需要及时消失。 是数据库连接吗? 是一些窗把手吗? 没关系。

另一个例子是,当您确实知道应该如何实现它时,例如尚不存在的对象的接口。 也许该对象应该由您的库的客户端提供,或者必须由不受您控制的完全不同的模块实现。 您基本上可以为类上可用的方法设计一个契约。

也就是说,我只在需要的地方使用它们。 如果我可以用常规类来完成它,或者如果它是特定对象固有的东西,我会将其设为一个类。 正如其他人所说,为每个类使用接口有一些优点,但这是太多的额外开销,我看不到它有什么可观的净收益。 大多数时候,我设计的类结构是平坦且宽阔的,并且具有尽可能少的依赖关系。

总之:如果您需要实现方式截然不同的通用功能,那么接口正是您所需要的。

Interfaces have many useful situations. When you need to add a specific behavior to a class that can be found across a wide variety of classes, that's a perfect time for an interface. A good example is the IDisposable interface - you have some resource that when you're done, needs to go away in a timely fashion. Is it a database connection? Is it some window handle? Doesn't matter.

Another example would be when you really don't know how it should be implemented, such as an interface to an object that doesn't exist yet. Perhaps the object should be supplied by a client of your library, or must be implemented by a completely different module not under your control. You can basically design a contract for the methods available on the class.

That said, I only use them where it's needed. If I can do it with a regular class, or if it's something intrinsic to the particular object, I'll make it a class. There are some advantages to using Interfaces for every class as others have said, but that's so much extra overhead that I don't see a decent net gain on it. Most of the time, I've designed my class structures so that they're flat and wide, with as few dependencies as possible.

In summary: If you have common functionality required that's implemented dramatically differently, an Interface is just what you need.

醉生梦死 2024-07-21 03:17:13

如果您想了解何时使用接口以及它们的用途是什么,我认为您应该看看这本书: 首先设计模式

这本书真正帮助我理解了界面的魅力。

在读这本书之前,我知道什么是接口,但我完全不知道什么时候应该使用它们。

If you want to understand when to use interfaces, and what is their use, I think you should take a look at the book: Head First Desing Patterns.

This is the book that really helped me understand what is so cool about interfaces.

Before reading this book, I knew what an interface was, but I had absolutely no idea about when should I use them.

南渊 2024-07-21 03:17:13

接口可以帮助您保持对抽象的依赖关系。

使用接口的代码仅依赖于接口,因此您知道对细节没有人为的依赖关系。 这为您将来更改代码提供了很大的自由,因为您确切地知道应该做什么和应该做什么。 当您“修复”错误或重构时不应该中断。

在我看来,这是良好代码设计的本质。

Interfaces help you keep the dependencies on the abstractions.

Code that uses the interface only depends on the interface, so you know that there are no artificial dependencies on the details. This gives you lots of freedom as far as changing code in the future, since you know exactly what should & shouldn't break when you 'fix' a bug or refactor.

In my opinion, it's the essence of good code design.

不可一世的女人 2024-07-21 03:17:13

“上面的人说他创建了另一个接口来处理新成员。没有任何破坏。

这不是组合吗?为什么不使用没有接口的组合?更灵活。”

您似乎正在从继承的角度考虑组合,例如“我将把所有这些功能继承到这个对象中来完成这项工作。” 这是一种糟糕的代码编写方式。 这就像说,“我想建造一座摩天大楼,所以我要学习所有需要知道的工作,从如何创建蓝图到如何打基础和安装照明......”

改为考虑构图就每个执行单个任务的单独对象而言。 为了完成复杂的工作,我现在可以依靠这些单独的对象来执行各自的任务。 这就像雇用建筑师和施工人员来建造摩天大楼一样。 我不需要详细了解他们每个人如何完成自己的工作,只要知道他们能够做到即可。 在代码中,这意味着将依赖项注入到对象中以执行复杂的任务而不是继承。

那么接口应该放在哪里呢? 它们是各个对象之间的契约。 它们使您能够不关心单独的具体实现。 它们允许您与一堆共享相同职责但实际上可能具有不同实现的对象使用通用语言。 接口成为执行任务的对象的抽象。 我不需要知道每个拿着锤子的人是如何工作的,只要他知道如何使用 HitNail() 即可。

当您开始使用许多具有单一职责的小类来编写复杂的代码系统时,您很快就会发现,如果您过于依赖给定类的具体实现,那么您可能会遇到严重的问题,并且该类开始发生变化...因此,我们不依赖具体的实现,而是创建一个接口 - 一个抽象。 我们说,“我不在乎你如何做 JobX,只关心你做了它。”

接口还有其他好处,如测试、模拟等……但这些并不是编写接口代码的原因。 原因是创建一个不依赖于具体细节并因此彼此高度耦合的代码系统。 这就是为什么,用你的图形思维大脑,你应该害怕将一堆具体的类相互耦合。 因为其中一个类的更改会引起连锁反应。

当您将自己耦合到抽象而不是具体的类时,您就限制了耦合。 你说,我只会跟我们双方都同意的合同结合,其他什么都不会。” 如果实现该契约的类更改了完成其任务的内部方式,您也不在乎,因为您不依赖于非契约属性或方法。 您仅依赖商定的合同。

"The guy above says he creates another interface to handle the new member(s). Nothing breaks.

Isn't that composition? Why not use composition without interfaces? More flexible."

You seem to be thinking of composition in terms of inheritance, as in, "I'll inherit all of these capabilities into this one object to do this job." That's a bad way to write code. It's like saying, "I want to build a skyscraper, so I'll learn every job there is to know, from how to create the blueprints on down to how to poor the foundation and install the lighting..."

Think of composition instead in terms of separate objects that each perform a single task. To do a complex job, I can now rely on these separate objects to perform their individual tasks. It's like hiring the architect and construction crew to build the skyscraper. I don't need to know in great details how they each do their job, just that they can do it. In code, this means injecting dependencies into an object to perform a complex tasks instead of inheriting.

So where to interfaces fit in? They're the contract between the individual objects. They allow you the ability to not care about individual, concrete implementations. They allow you to speak a common language with a bunch of objects that share the same responsibility, but may actually have different implementation. The interface becomes an abstraction to the object performing the task. I don't need to know how every single guy with a hammer works, just that he knows how to HitNail().

When you begin to compose complex system of code with lots of small classes that have single responsibilities, then you soon learn that you can run into serious problems if you rely too much on the concrete implementation of a given class, and that class begins to change... So instead of relying on the concrete implementation, we create an interface - an abstraction. And we say, "I don't care how you do JobX, only that you do it."

There are other benefits to interfaces like testing, mocking, etc... But those are not the reason to code to an interface. The reason is to create a system of code that isn't dependent on specifics and thus highly coupled to each other. This is why, with your graph thinking brain, you should be afraid of coupling a bunch of concrete classes to each other. Because changes in one of those classes will cause a ripple-effect.

When you couple yourself to an abstraction instead of a concrete class, you limit the coupling. You say, I"m only going to be coupled to the contract we both agree on, and nothing else." And if the class implementing that contract changes its internal way of completing its task, you don't care, because you aren't relying on a non-contract property or method. You're relying only on the agreed-upon contract.

魂ガ小子 2024-07-21 03:17:13

这是关于依赖性的。 您希望您的代码在适当的情况下依赖于接口类型而不是具体类型。 例如,您可能有多个具体类型,它们都执行类似的行为,但实现方式不同。 您是否希望您的代码库依赖于这些多种具体类型或一个接口? 当您需要进行更改时,您认为您的代码库有多灵活?

对于您不想通过使用组合来使用公共成员的观点,我想说您只是封装了不必要的依赖项。 如果您想使用组合,那么您可以通过组合接口类型而不是具体类型来大大减少依赖性。

要获得更好的解释,请尝试查看有关控制反转的文献。

It is about dependencies. You want your code to depend on interface types instead of concrete types where appropriate. For example, you might have multiple concrete types that all perform similar behavior but implement it differently. Do you want your code base to have dependencies on those multiple concrete types, or one interface? How flexible do you think your code base will be when you need to make changes?

To your point about not wanting to use public members by using composition, I would say you're just encapsulating unnecessary dependencies. If you want to use composition, then you greatly reduce dependencies by composing interface types instead of concrete types.

For a better explanation, try looking at the literature on inversion of control.

秋凉 2024-07-21 03:17:13

在依赖注入和 IoC 框架的上下文中,接口对我来说最有意义。 我喜欢这样的想法:您可以定义一组行为(方法)并通过接口的实现“保证”这些行为。 现在,您可以通过单个程序集和配置文件更新将全新功能插入现有系统。

有效的界面设计确实需要大量的前瞻性规划,我发现它们在大型系统和框架的环境中最有用。 当它们有用时,它们确实很有用。 我最喜欢的一些:

  • IComparable (您决定对象如何相互比较)
  • IQueryable (LINQ 有人吗?)
  • IDisposable (保留您的 < code>using 语句方便)

Interfaces make the most sense to me in the context of dependency injection and IoC frameworks. I like the idea that you can define a set of behaviors (methods) and "guarantee" those behaviors through the implementation of an interface. Now you can plug whole new functions into an existing system with a single assembly and a config file update.

Effective design of interfaces does require a good deal of forward planning, and I find they are most useful in the context of large systems and frameworks. When they're useful they're really useful. A few of my favorite:

  • IComparable (YOU decide how your objects compare against each other)
  • IQueryable (LINQ anyone?)
  • IDisposable (keep your using statement handy)
半窗疏影 2024-07-21 03:17:13

我认为您描述了自上而下的设计方法。
你不必这么做,但有时他真的很有帮助。

I think that you describe there top-down design method.
You don't have to do it, but sometimes he really help.

烟织青萝梦 2024-07-21 03:17:13

我会参考 .net 设计指南:
http://msdn.microsoft.com/en-us/library/ms229013。 aspx

使用接口的原因有很多,但我也发现它们常常因为错误的原因而被过度使用。 接口在处理值类型时提供了更大的灵活性,并且在处理集合等时非常有用,但是在为我自己的项目设计类层次结构时,我总是首先尝试考虑简单性,而接口通常会导致(不必要的)更复杂的情况。

我的经验法则是实现每个有意义的 BCL 接口,并且仅在我自己的接口实际提供非常有价值的东西时才将其添加到我的设计中。 我宁愿拥有抽象类 WidgetManager 并根据需要实现具体方法,而不是 IWidgetManager、IWidgetManager2 等。

I'd refer to the .net design guidelines on this:
http://msdn.microsoft.com/en-us/library/ms229013.aspx

There are a lot of reasons to use interfaces, but I also find that they're often overused for the wrong reasons. Interfaces provide much more flexibility when working with value types, and are incredibly useful when working with collections, etc, but when designing a class hierarchy for my own projects, I always try to think about simplicity first, and interfaces often lead to (unnecessarily) more complex situations.

My rule of thumb is to implement every BCL interface that makes sense, and only add my own interfaces into my designs when it actually provides something very valuable. Instead of having IWidgetManager, IWidgetManager2, etc... I'd much rather have abstract class WidgetManager and implement concrete methods as needed.

蓝咒 2024-07-21 03:17:13

这个人听起来像是误解了接口编程的概念。 它并不是指仅使用.Net/Java 中的interface 关键字进行编程,也不是仅使用C++ 中的纯虚函数进行类编程,该原则中提到的接口是高级接口。封装系统低级结构的结构。 与乘法一样,它封装了将数字添加到自身特定数量的重复的想法。 但是当我们说 3 * 2 时,我们并不关心它是 3 + 3、2 + 2 + 2 还是 (2 + 2) + 2,其中括号中的部分被缓存。 只要我们从中得到 6 分。

事实上,接口的概念可以由接口抽象类或它们的组合来填充,就像许多 GoF 模式的情况一样。 只是 interface 关键字有点模糊不清。

这很有趣。 这家伙的想法可能就是引发评论的原因,比如围绕 StackOverflow 第 38 集的评论。

This person sound like he misunderstood the concept of programming to an interface. It doesn't refer to programming using only the interface keyword in the .Net/Java or class with nothing but pure virtual functions in C++, The interface that are referred to in that principle are a high-level construct that encapsulates the low-level ones of a system. Like with multiplication, it encapsulates the idea of adding a number to itself a specific quantity of repetitions. But when we say 3 * 2 we don't care if it's 3 + 3, 2 + 2 + 2 or (2 + 2) + 2 where the part in parentheses is cached. So long as we receive a 6 from it.

As a matter of fact the concept of interfaces can be filled by an interface or abstract class or a combination of these as is the case with many of the GoF patterns. It's just that the interface keyword kind of clouds the water with ambiguity.

It's funny. This guy's kind of thinking is probably what's spawned comments such as the ones centering around StackOverflow episode #38.

冷︶言冷语的世界 2024-07-21 03:17:13

听起来你的朋友严重误用了界面。

我还见过到处都有界面的网络应用程序。 有些人似乎认为接口在某种程度上比常规方法签名更好。 简单的参数已经为我们提供了一个契约——在大多数情况下,我相信这已经足够了,并且可以使代码更简单。

在我看来,接口在 IDisposable 或 ICollection 等情况下最有用——它们指向对象期望的一组特定功能。 在这些情况下,它们似乎是完成这项工作的正确工具。

It sounds like your friend was seriously mis-using interfaces.

I've also seen web apps with interfaces all over the place. Some people seem to have the idea that an interface is somehow better than just a regular method signature. Simple parameters already provide us with a contract--in most cases I believe this is enough, and makes for simpler code.

It seems to me that interfaces are most useful in cases like IDisposable or ICollection -- where they point to a certain set of functionality to expect from an object. In these cases they appear to be the right tool for the job.

东京女 2024-07-21 03:17:13

我们在自定义 UI 元素上大量使用接口,其中每个元素都期望某种方法存在于另一个元素上(并且界面强制这种存在)。

We heavily use interfaces on custom UI elements, where each one is expecting a certain method to exist on another (and the interface forces that existence).

跨年 2024-07-21 03:17:13

接口的主要用途是允许实现的变化,从而允许在运行时切换代码。 这样做有很多原因/理由。

过去,有人认为系统中的每个类都应该有一个接口,但这被广泛认为是矫枉过正。 现在使用接口,其中类的实例可以作为系统操作的一部分进行更改(以表示状态):GoF 模式(例如策略和命令)捕获此用途,和/或需要替换系统的某些部分以进行测试(即依赖关系)注射)。 如果开发人员遵循测试驱动的开发实践,关键基础设施对象将具有接口。 这允许测试对这些对象进行“模拟”以测试系统的控制流。 接口的这种使用与里氏替换原则(OO 设计的原则之一)之间存在关系

。接口的另一种用途是标记接口,它不太关心调用者可以使用什么。 这是一种将元数据与类定义相关联的方法。 这可能会影响系统查看对象的方式(例如允许其序列化),或者它可能仅用作文档。

The primary use of an interface is to allow the variation of implementation allowing code to be switched at runtime. There are a number of reasons/rationale for doing this.

In the past some have argued that every class in the system should have an interface, but this is widely recognized as overkill. Interfaces are now used where instances of classes either can change as part of the system operation (to represent state): GoF patterns like Strategy and Command capture this use, and/or parts of the system need to be replaced for testing (ie. dependency injection). If developers are following test-driven development practices the key infrastructure objects will have interfaces. This allows tests to make "mocks" of these objects to test the system's flow-of-control. There is a relationship between this use of interface and the Liskov Substitution Principle (one of the principles of OO design)

A further use for interfaces which is less concerned with what is available to the caller, is the marker interface. Which is a way of associating metadata with the class definition. This may affect how the system views the object (for example allow it to be Serialized) or it might just serve as documentation.

九厘米的零° 2024-07-21 03:17:13

使用接口的最重要原因之一是它们允许我们为类编写单元测试并传递我们自己的依赖项。 通过将依赖项置于接口后面,我们在应用程序代码中打开了“接缝”,可以轻松地编写单元测试。 我没有看到许多答案中提到这个测试角度,但了解这一点非常重要:如果没有接口,这些依赖项(例如 Web 服务或文件系统引用)可能会变得非常难以测试或充其量都是很有条件的
我在这里写了一篇文章: http://jeffronay.com/why-use-an- interface/ 更详细地介绍了代码示例,显示了没有接口的 Service 类,然后使用接口重写了同一类,以演示使用接口时的测试灵活性。

One of the most important reasons for using an interface is the fact that they allow us to write unit tests for our classes and pass in our own dependencies. By putting the dependency behind an interface we open up "Seams" in our application code, where unit tests can easily be written. I don't see this test angle mentioned in many of the answers, but it is very important to understand that without interfaces, these dependencies (such as a web service, or a file system reference) can become very hard to test or at best are quite conditional.
I have written a post here: http://jeffronay.com/why-use-an-interface/ that goes into much more detail with code examples showing a Service class without an interface, and then the same class re-written using an interface to demonstrate the testing flexibility when using interfaces.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文