“程序”到接口的含义是什么?

发布于 2025-02-03 11:24:57 字数 337 浏览 6 评论 0 原文

我已经看到了几次提到的,但我不清楚它的含义。何时,为什么要这样做?

我知道界面有什么作用,但是我不清楚的事实使我认为我错过了正确使用它们。

是这样做的:

IInterface classRef = new ObjectWhatever()

您可以使用任何实现 iinterface 的类?您什么时候需要这样做?我唯一能想到的是,如果您有一种方法,并且不确定将传递哪些对象,除了IT实现 iinterface 。我认为您需要多久做一次。

另外,您如何编写一种使用实现接口的对象的方法?有可能吗?

I have seen this mentioned a few times and I am not clear on what it means. When and why would you do this?

I know what interfaces do, but the fact I am not clear on this makes me think I am missing out on using them correctly.

Is it just so if you were to do:

IInterface classRef = new ObjectWhatever()

You could use any class that implements IInterface? When would you need to do that? The only thing I can think of is if you have a method and you are unsure of what object will be passed except for it implementing IInterface. I cannot think how often you would need to do that.

Also, how could you write a method that takes in an object that implements an interface? Is that possible?

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

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

发布评论

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

评论(30

遮了一弯 2025-02-10 11:24:58

想象一下,您有一种称为“斑马”的产品,可以通过插件扩展。它通过在某些目录中搜索DLL来找到插件。它加载了所有这些DLL,并使用反射来找到实现 izebraplugin 的任何类,然后调用该接口的方法与插件进行通信。

这使其完全独立于任何特定的插件类 - 它不在乎类是什么。它只关心他们满足接口规范。

接口是定义这样的可扩展性点的一种方式。与接口进行交谈的代码更加松散地耦合 - 实际上,它根本没有与任何其他特定代码结合在一起。它可以与从未见过原始开发人员遇到的人撰写的插件相互互操作。

取而代之的是,您可以使用具有虚拟功能的基类 - 所有插件都将从基类派生。但这是更大的限制,因为类只能具有一个基类,而它可以实现任何数量的接口。

Imagine you have a product called 'Zebra' that can be extended by plugins. It finds the plugins by searching for DLLs in some directory. It loads all those DLLs and uses reflection to find any classes that implement IZebraPlugin, and then calls the methods of that interface to communicate with the plugins.

This makes it completely independent of any specific plugin class - it doesn't care what the classes are. It only cares that they fulfill the interface specification.

Interfaces are a way of defining points of extensibility like this. Code that talks to an interface is more loosely coupled - in fact it is not coupled at all to any other specific code. It can inter-operate with plugins written years later by people who have never met the original developer.

You could instead use a base class with virtual functions - all plugins would be derived from the base class. But this is much more limiting because a class can only have one base class, whereas it can implement any number of interfaces.

默嘫て 2025-02-10 11:24:58

C ++解释。

将界面视为您的类公共方法。

然后,您可以创建一个模板,该模板“取决于”这些公共方法以执行其自己的函数(在类公共接口中定义了函数调用)。假设此模板是一个容器,例如向量类,其依赖的接口是搜索算法。

任何定义函数/接口向量的算法类都可以呼叫以满足“合同”(正如某人在原始答复中所解释的那样)。这些算法甚至不需要是同一基类。唯一的要求是,在算法中定义了向量取决于(接口)的函数/方法。

所有这些的目的是,您可以提供任何不同的搜索算法/类,只要它提供了向量依赖的接口(气泡搜索,顺序搜索,快速搜索)。

您可能还需要设计其他容器(列表,队列),这些容器可以通过使搜索算法依赖于搜索算法的接口/合同来利用与向量相同的搜索算法。

这节省了时间(oop原理“代码重复使用”),因为您能够一次又一次地编写算法,而不是一次又一次地特定于您创建的每个新对象,而不会用过度生长的继承树过度复杂问题。

至于事物的运作方式“错过”;大型时间(至少在C ++中),因为这是大多数标准模板库的框架的运作方式。

当然,当使用继承和抽象类时,编程到接口的方法会更改;但是原理是相同的,您的公共功能/方法是您的类接口。

这是一个巨大的话题,也是设计模式的基石原则之一。

C++ explanation.

Think of an interface as your classes public methods.

You then could create a template that 'depends' on these public methods in order to carry out it's own function (it makes function calls defined in the classes public interface). Lets say this template is a container, like a Vector class, and the interface it depends on is a search algorithm.

Any algorithm class that defines the functions/interface Vector makes calls to will satisfy the 'contract' (as someone explained in the original reply). The algorithms don't even need to be of the same base class; the only requirement is that the functions/methods that the Vector depends on (interface) is defined in your algorithm.

The point of all of this is that you could supply any different search algorithm/class just as long as it supplied the interface that Vector depends on (bubble search, sequential search, quick search).

You might also want to design other containers (lists, queues) that would harness the same search algorithm as Vector by having them fulfill the interface/contract that your search algorithms depends on.

This saves time (OOP principle 'code reuse') as you are able to write an algorithm once instead of again and again and again specific to every new object you create without over-complicating the issue with an overgrown inheritance tree.

As for 'missing out' on how things operate; big-time (at least in C++), as this is how most of the Standard TEMPLATE Library's framework operates.

Of course when using inheritance and abstract classes the methodology of programming to an interface changes; but the principle is the same, your public functions/methods are your classes interface.

This is a huge topic and one of the the cornerstone principles of Design Patterns.

卸妝后依然美 2025-02-10 11:24:58

在Java中,这些具体类都实现了CharSequence接口:

charbuffer,string,StringBuffer,StringBuilder

这些具体类除了对象以外没有其他父母类别,因此除了它们每个人都与字符的数组有关,代表这样的事实或操纵此类此类事实以外,没有任何关系。例如,一旦实例化字符串对象,就无法更改字符串的字符,而可以编辑StringBuffer或StringBuilder的字符。

然而,这些类中的每个类都可以适当地实现CharSequence接口方法:

char charAt(int index)
int length()
CharSequence subSequence(int start, int end)
String toString()

在某些情况下,已对字符串的Java类库类已修改为现在接受CharSequence接口。因此,如果您具有StringBuilder的实例,而不是提取字符串对象(这意味着实例化新对象实例),而是可以在实现CharSequence接口时传递StringBuilder本身。

对于任何情况下,可以将字符附加到基础混凝土类对象实例的实例的任何情况下,某些类实现的辅助接口具有相同的好处。所有这些具体类都实现了附加界面:

BufferedWriter,Chararraywriter,Charbuffer,Filewriter,FilterWriter,LogStream,utputStreamWriter,PipedWriter,PipedWriter,PrintStream,PrintStream,printwriter,StringBuffer,StringBuilder,StringBuilder,String Writer,Writer

>

In Java these concrete classes all implement the CharSequence interface:

CharBuffer, String, StringBuffer, StringBuilder

These concrete classes do not have a common parent class other than Object, so there is nothing that relates them, other than the fact they each have something to do with arrays of characters, representing such, or manipulating such. For instance, the characters of String cannot be changed once a String object is instantiated, whereas the characters of StringBuffer or StringBuilder can be edited.

Yet each one of these classes is capable of suitably implementing the CharSequence interface methods:

char charAt(int index)
int length()
CharSequence subSequence(int start, int end)
String toString()

In some cases, Java class library classes that used to accept String have been revised to now accept the CharSequence interface. So if you have an instance of StringBuilder, instead of extracting a String object (which means instantiating a new object instance), it can instead just pass the StringBuilder itself as it implements the CharSequence interface.

The Appendable interface that some classes implement has much the same kind of benefit for any situation where characters can be appended to an instance of the underlying concrete class object instance. All of these concrete classes implement the Appendable interface:

BufferedWriter, CharArrayWriter, CharBuffer, FileWriter, FilterWriter, LogStream, OutputStreamWriter, PipedWriter, PrintStream, PrintWriter, StringBuffer, StringBuilder, StringWriter, Writer

生来就爱笑 2025-02-10 11:24:58

界面的程序是GOF书籍中的一个术语。我不会直接说这与Java接口有关,而是真正的接口。为了实现干净的图层分离,您需要在系统之间创建一些分离:例如,假设您有一个要使用的具体数据库,您永远不会“到数据库”,而是将“对存储接口”进行“程序”。同样,您永远不会“编程到Web服务”,而是将其编程到“客户端接口”。这样您就可以轻松地将内容交换。

我发现这些规则对我有帮助:

1 。当我们拥有多种类型的对象时,我们使用Java接口。如果我只有一个对象,我看不到这一点。如果至少有两个具体的想法实现,那么我将使用Java接口。

2 。如果如上所述,您想将与外部系统(存储系统)的分离带到您自己的系统(本地DB),然后还使用接口。

注意如何考虑何时使用它们的方法。

program to an interface is a term from the GOF book. i would not directly say it has to do with java interface but rather real interfaces. to achieve clean layer separation, you need to create some separation between systems for example: Let's say you had a concrete database you want to use, you would never "program to the database" , instead you would "program to the storage interface". Likewise you would never "program to a Web Service" but rather you would program to a "client interface". this is so you can easily swap things out.

i find these rules help me:

1. we use a java interface when we have multiple types of an object. if i just have single object, i dont see the point. if there are at least two concrete implementations of some idea, then i would use a java interface.

2. if as i stated above, you want to bring decoupling from an external system (storage system) to your own system (local DB) then also use a interface.

notice how there are two ways to consider when to use them.

怎言笑 2025-02-10 11:24:58

接口就像合同,您希望您的实现类实现合同中编写的方法(接口)。由于Java没有提供多种继承,因此“编程到接口”是实现多重继承的好方法。

如果您有一个已经扩展了其他B类的A类,但是您希望该类也遵循某些准则或执行某个合同,那么您可以通过“编程到接口”策略来做到这一点。

An interface is like a contract, where you want your implementation class to implement methods written in the contract (interface). Since Java does not provide multiple inheritance, "programming to interface" is a good way to achieve multiple inheritance.

If you have a class A that is already extending some other class B, but you want that class A to also follow certain guidelines or implement a certain contract, then you can do so by the "programming to interface" strategy.

凡间太子 2025-02-10 11:24:58

Q: - ...“您可以使用任何实现接口的类吗?”
答: - 是。

问: - ...“您什么时候需要这样做?”
答: - 每次需要一个实现接口的类。

注意: 我们无法实例化类未实现的接口 - true。

  • 为什么?
  • 因为界面仅具有方法原型,而不具有定义(仅功能名称,而不是其逻辑)

anintf aninst = new Aclass();
// 我们只有在 Aclass实现Anintf的情况下才能执行此操作。
// ANINST将具有aclass参考。


注意: 现在,我们可以理解如果BCLASS和CCLASS实现了相同的dintf。

Dintf bInst = new Bclass();  
// now we could call all Dintf functions implemented (defined) in Bclass.

Dintf cInst = new Cclass();  
// now we could call all Dintf functions implemented (defined) in Cclass.

我们拥有的内容:相同的接口原型(界面中的函数名称)并调用不同的实现。

参考书目:
prototypes -wikipedia

Q: - ... "Could you use any class that implements an interface?"
A: - Yes.

Q: - ... "When would you need to do that?"
A: - Each time you need a class(es) that implements interface(s).

Note: We couldn't instantiate an interface not implemented by a class - True.

  • Why?
  • Because the interface has only method prototypes, not definitions (just functions names, not their logic)

AnIntf anInst = new Aclass();
// we could do this only if Aclass implements AnIntf.
// anInst will have Aclass reference.


Note: Now we could understand what happened if Bclass and Cclass implemented same Dintf.

Dintf bInst = new Bclass();  
// now we could call all Dintf functions implemented (defined) in Bclass.

Dintf cInst = new Cclass();  
// now we could call all Dintf functions implemented (defined) in Cclass.

What we have: Same interface prototypes (functions names in interface), and call different implementations.

Bibliography:
Prototypes - wikipedia

小耗子 2025-02-10 11:24:58

编码界面是一种理念,而不是特定的语言构造或设计模式 - 它指示您要遵循的正确步骤顺序,以创建更好的软件系统 (例如,更具弹性,更可检验,更可扩展,更扩展和其他良好的特征)。

实际上是:

====

在跳入实现和编码(How)之前 - 想到什么:

  • 黑匣子应该构成您的系统,
  • 什么是每个盒子的责任,
  • 每个“客户”(即其他盒子之一,第三方“盒子”,甚至人类)应与之交流(每个盒子的API)的方式。

之后,您可以弄清楚上述内容,然后继续实现这些框(如何)。

首先思考一个盒子'是什么,以及它的API,导致开发人员将盒子的责任提高,并为自己和未来的开发人员标记其暴露的细节(“ API”)与它的隐藏细节(​​”实施细节”),这是一个非常重要的差异化。

一个即时且容易明显的收益是团队可以在不影响一般体系结构的情况下改变和改善实现。它还使系统更容易测试(与TDD方法搭配得很好)。

===
除了我上面提到的特征之外,您还节省了很多时间朝这个方向发展。

Micro Services和DDD正确完成时,是“编码到接口”的绝佳示例,但是该概念以从巨石到“无server be to fe,从OOP到功能等”等的每种模式赢得了胜利

。强烈建议使用这种软件工程方法(我基本上认为这在其他领域也是完全有意义的)。

Coding to an interface is a philosophy, rather than specific language constructs or design patterns - it instructs you what is the correct order of steps to follow in order to create better software systems (e.g. more resilient, more testable, more scalable, more extendible, and other nice traits).

What it actually means is:

===

Before jumping to implementations and coding (the HOW) - think of the WHAT:

  • What black boxes should make up your system,
  • What is each box' responsibility,
  • What are the ways each "client" (that is, one of those other boxes, 3rd party "boxes", or even humans) should communicate with it (the API of each box).

After you figure the above, go ahead and implement those boxes (the HOW).

Thinking first of what a box' is and what its API, leads the developer to distil the box' responsibility, and to mark for himself and future developers the difference between what is its exposed details ("API") and it's hidden details ("implementation details"), which is a very important differentiation to have.

One immediate and easily noticeable gain is the team can then change and improve implementations without affecting the general architecture. It also makes the system MUCH more testable (it goes well with the TDD approach).

===
Beyond the traits I've mentioned above, you also save A LOT OF TIME going this direction.

Micro Services and DDD, when done right, are great examples of "Coding to an interface", however the concept wins in every pattern from monoliths to "serverless", from BE to FE, from OOP to functional, etc....

I strongly recommend this approach for Software Engineering (and I basically believe it makes total sense in other fields as well).

把人绕傻吧 2025-02-10 11:24:58

将接口的程序允许更改由接口定义的合同的实现。它允许在合同和特定实现之间散布耦合。

iinterface classRef = new object what what what what whate()

您可以使用任何实现Iinterface的类?您什么时候需要这样做?

以一个很好的例子来看一下这个问题。

为什么要与Java类互动首选?

使用接口命中性能?

如果是多少?

是的。在子秒中,它将在开销中略有性能。但是,如果您的应用程序需要动态更改接口的实现,请不要担心性能影响。

如何避免它而不必维护两个代码?

如果您的应用程序需要,请勿尝试避免多个接口的实现。如果没有一个特定的实现接口的紧密耦合,则可能必须部署补丁以将一个实现更改为另一个实现。

一种好的用例:策略模式的实施:

Program to an interface allows to change implementation of contract defined by interface seamlessly. It allows loose coupling between contract and specific implementations.

IInterface classRef = new ObjectWhatever()

You could use any class that implements IInterface? When would you need to do that?

Have a look at this SE question for good example.

Why should the interface for a Java class be preferred?

does using an Interface hit performance?

if so how much?

Yes. It will have slight performance overhead in sub-seconds. But if your application has requirement to change the implementation of interface dynamically, don't worry about performance impact.

how can you avoid it without having to maintain two bits of code?

Don't try to avoid multiple implementations of interface if your application need them. In absence of tight coupling of interface with one specific implementation, you may have to deploy the patch to change one implementation to other implementation.

One good use case: Implementation of Strategy pattern:

Real World Example of the Strategy Pattern

陪我终i 2025-02-10 11:24:58

“接口程序”是指无法正确提供硬码,这意味着您的代码应在不破坏先前功能的情况下扩展。只是扩展,而不是编辑上一个代码。

"Program to interface" means don't provide hard code right the way, meaning your code should be extended without breaking the previous functionality. Just extensions, not editing the previous code.

纸伞微斜 2025-02-10 11:24:58

另外,我在这里看到了很多好的解释性答案,因此我想在这里给出我的观点,包括一些额外的信息,我在使用此方法时注意到了什么。

单位测试

在过去两年中,我写了一个爱好项目,但我没有为此编写单位测试。在写了大约50k行后,我发现确实有必要编写单元测试。
我没有使用接口(或很少)...当我进行第一个单元测试时,我发现它很复杂。为什么?

因为我必须制作大量的类实例,用于输入作为类变量和/或参数。因此,测试看起来更像是集成测试(由于所有这些都捆绑在一起,因此必须制作一个完整的课程“框架”)。

害怕界面
因此,我决定使用界面。我担心我必须多次(在所有二手班上)到处实施所有功能。但是,在某种程度上,这是正确的,通过使用继承可以减少很多。

界面和继承的组合
我发现这种组合非常好。我给出一个非常简单的例子。

public interface IPricable
{
    int Price { get; }
}

public interface ICar : IPricable

public abstract class Article
{
    public int Price { get { return ... } }
}

public class Car : Article, ICar
{
    // Price does not need to be defined here
}

这样,不需要复制代码,同时仍然具有将汽车作为接口(ICAR)的好处。

Also I see a lot of good and explanatory answers here, so I want to give my point of view here, including some extra information what I noticed when using this method.

Unit testing

For the last two years, I have written a hobby project and I did not write unit tests for it. After writing about 50K lines I found out it would be really necessary to write unit tests.
I did not use interfaces (or very sparingly) ... and when I made my first unit test, I found out it was complicated. Why?

Because I had to make a lot of class instances, used for input as class variables and/or parameters. So the tests look more like integration tests (having to make a complete 'framework' of classes since all was tied together).

Fear of interfaces
So I decided to use interfaces. My fear was that I had to implement all functionality everywhere (in all used classes) multiple times. In some way this is true, however, by using inheritance it can be reduced a lot.

Combination of interfaces and inheritance
I found out the combination is very good to be used. I give a very simple example.

public interface IPricable
{
    int Price { get; }
}

public interface ICar : IPricable

public abstract class Article
{
    public int Price { get { return ... } }
}

public class Car : Article, ICar
{
    // Price does not need to be defined here
}

This way copying code is not necessary, while still having the benefit of using a car as interface (ICar).

月寒剑心 2025-02-10 11:24:57

这里有一些很棒的答案,这些问题涉及有关接口和松散耦合代码,控制倒置等的各种细节。有一些相当令人愉悦的讨论,所以我想借此机会分解一些东西,以了解为什么界面有用。

当我第一次开始接触界面时,我也对它们的相关性感到困惑。我不明白你为什么需要它们。如果我们使用诸如Java或C#之类的语言,我们已经具有继承,我将接口视为的继承和思想形式,“为什么要打扰?”从某种意义上说,我是对的,您可以将界面视为一种薄弱的继承形式,但是除此之外潜在的许多非相关对象类别。

例如 - 假设您有一个SIM卡游戏,并且有以下类:

class HouseFly inherits Insect {
    void FlyAroundYourHead(){}
    void LandOnThings(){}
}

class Telemarketer inherits Person {
    void CallDuringDinner(){}
    void ContinueTalkingWhenYouSayNo(){}
}

显然,这两个对象在直接继承方面没有任何共同点。但是,您可以说他们都很烦人。

假设我们的游戏需要有某种随机的东西在吃晚餐时会惹恼游戏玩家。这可能是 Housefly Telemarketer 或两者兼而有之 - 但是您如何使用一个功能允许两者兼而有之呢?您如何以相同的方式要求每种不同类型的对象“做他们烦人的事情”?

要意识到的关键是,电话推销 housefly 共享一个常见的松散解释的行为,即使它们在建模方面绝不相似。因此,让我们制作一个可以实现的接口:

interface IPest {
    void BeAnnoying();
}

class HouseFly inherits Insect implements IPest {
    void FlyAroundYourHead(){}
    void LandOnThings(){}

    void BeAnnoying() {
        FlyAroundYourHead();
        LandOnThings();
    }
}

class Telemarketer inherits Person implements IPest {
    void CallDuringDinner(){}
    void ContinueTalkingWhenYouSayNo(){}

    void BeAnnoying() {
        CallDuringDinner();
        ContinueTalkingWhenYouSayNo();
    }
}

我们现在有两个类,每个类都可以以自己的方式感到烦人。而且他们不需要从同一基类来衍生并共享共同的固有特征 - 他们只需要满足 ipest 的合同 - 合同很简单。您只需要 beannoying 。在这方面,我们可以对以下内容进行建模:

class DiningRoom {

    DiningRoom(Person[] diningPeople, IPest[] pests) { ... }

    void ServeDinner() {
        when diningPeople are eating,

        foreach pest in pests
        pest.BeAnnoying();
    }
}

在这里,我们有一个餐厅,可以接受许多食客和许多害虫 - 请注意使用该界面。这意味着,在我们的小世界中,害虫的成员数组实际上可以是 Telemarketer 对象或 Housefly 对象。

serveinner 方法在晚餐时被称为,我们的饭厅里的人应该吃。在我们的小游戏中,那是我们的害虫完成工作的时候 - 每个害虫都被指示通过 ipest 接口感到烦人。这样,我们可以很容易地拥有 Telemarketers Houseflys 以每种方式都很烦人 - 我们只关心我们在餐厅中有东西< /code>是害虫的对象,我们并不真正在乎它是什么,它们与他人无关。

这个非常人为的伪代码示例(在我预期的时间比我预期的要长得多)只是为了说明那种最终从何时使用界面来为我开启的东西。对于这个例子的愚蠢,我提前道歉,但希望它有助于您的理解。而且,可以肯定的是,您在此处收到的其他发布的答案确实涵盖了当今在设计模式和开发方法中使用界面的范围。

There are some wonderful answers on here to this questions that get into all sorts of great detail about interfaces and loosely coupling code, inversion of control and so on. There are some fairly heady discussions, so I'd like to take the opportunity to break things down a bit for understanding why an interface is useful.

When I first started getting exposed to interfaces, I too was confused about their relevance. I didn't understand why you needed them. If we're using a language like Java or C#, we already have inheritance and I viewed interfaces as a weaker form of inheritance and thought, "why bother?" In a sense I was right, you can think of interfaces as sort of a weak form of inheritance, but beyond that I finally understood their use as a language construct by thinking of them as a means of classifying common traits or behaviors that were exhibited by potentially many non-related classes of objects.

For example -- say you have a SIM game and have the following classes:

class HouseFly inherits Insect {
    void FlyAroundYourHead(){}
    void LandOnThings(){}
}

class Telemarketer inherits Person {
    void CallDuringDinner(){}
    void ContinueTalkingWhenYouSayNo(){}
}

Clearly, these two objects have nothing in common in terms of direct inheritance. But, you could say they are both annoying.

Let's say our game needs to have some sort of random thing that annoys the game player when they eat dinner. This could be a HouseFly or a Telemarketer or both -- but how do you allow for both with a single function? And how do you ask each different type of object to "do their annoying thing" in the same way?

The key to realize is that both a Telemarketer and HouseFly share a common loosely interpreted behavior even though they are nothing alike in terms of modeling them. So, let's make an interface that both can implement:

interface IPest {
    void BeAnnoying();
}

class HouseFly inherits Insect implements IPest {
    void FlyAroundYourHead(){}
    void LandOnThings(){}

    void BeAnnoying() {
        FlyAroundYourHead();
        LandOnThings();
    }
}

class Telemarketer inherits Person implements IPest {
    void CallDuringDinner(){}
    void ContinueTalkingWhenYouSayNo(){}

    void BeAnnoying() {
        CallDuringDinner();
        ContinueTalkingWhenYouSayNo();
    }
}

We now have two classes that can each be annoying in their own way. And they do not need to derive from the same base class and share common inherent characteristics -- they simply need to satisfy the contract of IPest -- that contract is simple. You just have to BeAnnoying. In this regard, we can model the following:

class DiningRoom {

    DiningRoom(Person[] diningPeople, IPest[] pests) { ... }

    void ServeDinner() {
        when diningPeople are eating,

        foreach pest in pests
        pest.BeAnnoying();
    }
}

Here we have a dining room that accepts a number of diners and a number of pests -- note the use of the interface. This means that in our little world, a member of the pests array could actually be a Telemarketer object or a HouseFly object.

The ServeDinner method is called when dinner is served and our people in the dining room are supposed to eat. In our little game, that's when our pests do their work -- each pest is instructed to be annoying by way of the IPest interface. In this way, we can easily have both Telemarketers and HouseFlys be annoying in each of their own ways -- we care only that we have something in the DiningRoom object that is a pest, we don't really care what it is and they could have nothing in common with other.

This very contrived pseudo-code example (that dragged on a lot longer than I anticipated) is simply meant to illustrate the kind of thing that finally turned the light on for me in terms of when we might use an interface. I apologize in advance for the silliness of the example, but hope that it helps in your understanding. And, to be sure, the other posted answers you've received here really cover the gamut of the use of interfaces today in design patterns and development methodologies.

夏九 2025-02-10 11:24:57

我用来给学生给学生的具体示例是,他们应该在简短的程序中写下

List myList = new ArrayList(); // programming to the List interface

这些

ArrayList myList = new ArrayList(); // this is bad

外观,但如果您继续在程序中使用 myList 100次,则可以开始看到差异。第一个声明可确保您仅在 myList 上调用方法,该方法由 list 接口定义(因此no arraylist 特定方法)。如果您以这种方式编程到界面,则稍后您可以决定确实需要

List myList = new TreeList();

,只需要在该位置更改代码即可。您已经知道,其余代码不会通过更改实现而破坏的任何事情,因为您已编程为接口

当您谈论方法参数和返回值时,好处更为明显(我认为)。以此为例:

public ArrayList doSomething(HashMap map);

该方法声明将您与两个具体实现相关联( arraylist hashmap )。一旦从其他代码调用该方法,对这些类型的任何更改都可能意味着您也必须更改调用代码。更好地编程到接口。

public List doSomething(Map map);

现在,您返回哪种 list map 作为参数传递。您在 dosomething 方法中所做的更改不会迫使您更改调用代码。

The specific example I used to give to students is that they should write

List myList = new ArrayList(); // programming to the List interface

instead of

ArrayList myList = new ArrayList(); // this is bad

These look exactly the same in a short program, but if you go on to use myList 100 times in your program you can start to see a difference. The first declaration ensures that you only call methods on myList that are defined by the List interface (so no ArrayList specific methods). If you've programmed to the interface this way, later on you can decide that you really need

List myList = new TreeList();

and you only have to change your code in that one spot. You already know that the rest of your code doesn't do anything that will be broken by changing the implementation because you programmed to the interface.

The benefits are even more obvious (I think) when you're talking about method parameters and return values. Take this for example:

public ArrayList doSomething(HashMap map);

That method declaration ties you to two concrete implementations (ArrayList and HashMap). As soon as that method is called from other code, any changes to those types probably mean you're going to have to change the calling code as well. It would be better to program to the interfaces.

public List doSomething(Map map);

Now it doesn't matter what kind of List you return, or what kind of Map is passed in as a parameter. Changes that you make inside the doSomething method won't force you to change the calling code.

梦途 2025-02-10 11:24:57

界面上的编程说:“我需要此功能,我不在乎它来自何处。”

考虑(在Java中), list 接口与 arraylist linkedlist 混凝土类。如果我关心的只是我有一个数据结构,其中包含我应该通过迭代访问的多个数据项,我会选择 list (这是99%的时间)。如果我知道我需要从列表的任何一端中恒定插入/删除,我可能会选择 linkedlist 具体实现(或更可能,使用 queue 接口)。如果我知道我需要通过索引随机访问,我会选择 arraylist 具体类。

Programming to an interface is saying, "I need this functionality and I don't care where it comes from."

Consider (in Java), the List interface versus the ArrayList and LinkedList concrete classes. If all I care about is that I have a data structure containing multiple data items that I should access via iteration, I'd pick a List (and that's 99% of the time). If I know that I need constant-time insert/delete from either end of the list, I might pick the LinkedList concrete implementation (or more likely, use the Queue interface). If I know I need random access by index, I'd pick the ArrayList concrete class.

黯淡〆 2025-02-10 11:24:57

对接口进行编程与我们在Java或.NET中看到的抽象接口无关。这甚至不是OOP概念。

这意味着不要与对象或数据结构的内部杂乱无章。使用抽象程序接口或API与您的数据进行交互。在Java或C#中,意味着使用公共属性和方法而不是原始字段访问。对于C,意味着使用函数而不是原始指针。

编辑:,使用数据库意味着使用视图和存储过程而不是直接访问。

Programming to an interface has absolutely nothing to do with abstract interfaces like we see in Java or .NET. It isn't even an OOP concept.

What it means is don't go messing around with the internals of an object or data structure. Use the Abstract Program Interface, or API, to interact with your data. In Java or C# that means using public properties and methods instead of raw field access. For C that means using functions instead of raw pointers.

EDIT: And with databases it means using views and stored procedures instead of direct table access.

放肆 2025-02-10 11:24:57

使用接口是使您的代码易于测试的关键因素,除了删除类之间的不必要的耦合。通过创建一个定义类上操作的界面,您允许类似于使用该功能的类,而无需直接依赖实现类,可以使用它。如果以后您决定更改和使用其他实现,则只需要更改实例实例化的代码部分即可。代码的其余部分不需要更改,因为它取决于接口,而不是实现类。

这对于创建单元测试非常有用。在正在测试的类中,您将其取决于接口,并将接口的实例注入类(或允许其根据需要构建接口实例的工厂)通过构造函数或属性settor构建界面实例。该类在其方法中使用提供的(或创建)接口。当您编写测试时,您可以模拟或伪造接口,并提供一个接口,该接口在单元测试中配置的数据响应。您可以这样做,因为您正在测试的课程仅与接口有关,而不是您的具体实现。任何实现界面的类,包括您的模拟或假班,都可以做到。

编辑:以下是一篇文章的链接,埃里希·伽玛(Erich Gamma)讨论了他的报价“界面的程序,而不是实现”。

http://www.artima.com/lejava/lejava/lejava/articles/articles/designprinciples.htmiples.html

Using interfaces is a key factor in making your code easily testable in addition to removing unnecessary couplings between your classes. By creating an interface that defines the operations on your class, you allow classes that want to use that functionality the ability to use it without depending on your implementing class directly. If later on you decide to change and use a different implementation, you need only change the part of the code where the implementation is instantiated. The rest of the code need not change because it depends on the interface, not the implementing class.

This is very useful in creating unit tests. In the class under test you have it depend on the interface and inject an instance of the interface into the class (or a factory that allows it to build instances of the interface as needed) via the constructor or a property settor. The class uses the provided (or created) interface in its methods. When you go to write your tests, you can mock or fake the interface and provide an interface that responds with data configured in your unit test. You can do this because your class under test deals only with the interface, not your concrete implementation. Any class implementing the interface, including your mock or fake class, will do.

EDIT: Below is a link to an article where Erich Gamma discusses his quote, "Program to an interface, not an implementation."

http://www.artima.com/lejava/articles/designprinciples.html

幸福丶如此 2025-02-10 11:24:57

您应该研究控制的反转:

在这种情况下,您不会写这篇文章

IInterface classRef = new ObjectWhatever();

:类似的内容:

IInterface classRef = container.Resolve<IInterface>();

这将进入 container 对象中的基于规则的设置,并为您构造实际对象,这可能是对象的。重要的是,您可以用完全使用其他类型对象的东西替换此规则,并且您的代码仍然可以使用。

如果我们将IOC放在桌子上,您可以编写知道它可以与对象进行特定的对象的代码,但不能与对象进行交谈,但不能与哪种类型的对象或如何做。

传递参数时,这将派上用场。

至于您的括号问题:“另外,您如何编写一种使用实现接口的对象的方法?这是可能的吗?”,在C#中,您将简单地将接口类型用于参数

public void DoSomethingToAnObject(IInterface whatever) { ... }

类型进入“与做一些特定事物的对象交谈”。上面定义的方法知道对对象的期望,它会在i Interface中实现所有内容,但是它不在乎它是哪种类型的对象,只有它遵守合同,这就是接口。

例如,您可能会熟悉计算器,并且可能在您的日子里使用了很多,但是大多数情况下它们都不同。另一方面,您知道标准计算器应该如何工作,因此即使您无法使用每个计算器所没有的特定功能,也可以使用它们。

这是界面的美丽。您可以编写一个代码,知道它会将对象传递给它,它可以期望某些行为。它不在乎一个hoot是什么样的对象,只是它支持所需的行为。

让我给你一个具体的例子。

我们有一个用于Windows表单的定制翻译系统。该系统通过表单上的控件循环并翻译每个文本。该系统知道如何处理基本控件,例如控制型的型式控制,以及类似的基本内容,但是对于任何基本的东西,它都会降低。

现在,由于控制从我们无法控制的预定义类继承的控制,我们可以做三件事之一:

  1. 建立对我们的翻译系统的支持,以专门检测其正在使用的哪种控制类型,并翻译正确的位(维护)噩梦)
  2. 将支持构建为基础类(不可能,因为所有控件都从不同的预定义类继承)
  3. 添加接口支持

,因此我们做了NR。 3。我们所有的控件都实现了iLocalizable,这是一个界面,它为我们提供了一种方法,即将“本身”转换为翻译文本/规则容器的能力。因此,该表单不需要知道它发现了哪种控制,只能实现特定的接口,并且知道有一种可以调用以定位控件的方法。

You should look into Inversion of Control:

In such a scenario, you wouldn't write this:

IInterface classRef = new ObjectWhatever();

You would write something like this:

IInterface classRef = container.Resolve<IInterface>();

This would go into a rule-based setup in the container object, and construct the actual object for you, which could be ObjectWhatever. The important thing is that you could replace this rule with something that used another type of object altogether, and your code would still work.

If we leave IoC off the table, you can write code that knows that it can talk to an object that does something specific, but not which type of object or how it does it.

This would come in handy when passing parameters.

As for your parenthesized question "Also, how could you write a method that takes in an object that implements an Interface? Is that possible?", in C# you would simply use the interface type for the parameter type, like this:

public void DoSomethingToAnObject(IInterface whatever) { ... }

This plugs right into the "talk to an object that does something specific." The method defined above knows what to expect from the object, that it implements everything in IInterface, but it doesn't care which type of object it is, only that it adheres to the contract, which is what an interface is.

For instance, you're probably familiar with calculators and have probably used quite a few in your days, but most of the time they're all different. You, on the other hand, knows how a standard calculator should work, so you're able to use them all, even if you can't use the specific features that each calculator has that none of the other has.

This is the beauty of interfaces. You can write a piece of code, that knows that it will get objects passed to it that it can expect certain behavior from. It doesn't care one hoot what kind of object it is, only that it supports the behavior needed.

Let me give you a concrete example.

We have a custom-built translation system for windows forms. This system loops through controls on a form and translate text in each. The system knows how to handle basic controls, like the-type-of-control-that-has-a-Text-property, and similar basic stuff, but for anything basic, it falls short.

Now, since controls inherit from pre-defined classes that we have no control over, we could do one of three things:

  1. Build support for our translation system to detect specifically which type of control it is working with, and translate the correct bits (maintenance nightmare)
  2. Build support into base classes (impossible, since all the controls inherit from different pre-defined classes)
  3. Add interface support

So we did nr. 3. All our controls implement ILocalizable, which is an interface that gives us one method, the ability to translate "itself" into a container of translation text/rules. As such, the form doesn't need to know which kind of control it has found, only that it implements the specific interface, and knows that there is a method where it can call to localize the control.

音盲 2025-02-10 11:24:57

界面的代码不是与Java无关,也没有其界面构造。< / strong>

这个概念在四本书的模式 /帮派中引起了人们的关注,但很可能在此之前就在附近。 概念肯定存在于Java存在之前。

这个 比原始意图。但是,这是我们在Java,C ++,C#等中拥有公共和私人方法和属性的原因。

这意味着只需与对象或系统的公共接口进行交互。不用担心,甚至预料它在内部做什么。不必担心它是如何实施的。在面向对象的代码中,这就是为什么我们有公共方法和私有方法/属性的原因。我们打算使用公共方法,因为私人方法仅在同类中内部使用。他们构成了班级的实现,可以根据需要更改而无需更改公共接口。假设关于功能,每次用相同的参数调用它时,类上的方法将执行相同的操作,并具有相同的预期结果。它允许作者更改班级的工作方式,其实施方式,而无需破坏人们如何与之互动。

您可以在接口上编程,而不是不使用接口构造的实现。您可以将其编程到接口而不是C ++中的实现,而C ++没有接口构造。只要两个大型企业系统通过公共接口(合同)进行交互,而不是在系统内部的对象上调用方法,就可以更加牢固地集成。预期,在给定相同的输入参数的情况下,界面始终以相同的预期方式做出反应。如果实现到接口而不是实现。这个概念在许多地方起作用。

摇晃认为Java界面与“界面到界面而不是实现”的概念有任何关系的想法。他们可以帮助应用这个概念,但它们不是这个概念。

Code to the Interface Not the Implementation has NOTHING to do with Java, nor its Interface construct.

This concept was brought to prominence in the Patterns / Gang of Four books but was most probably around well before that. The concept certainly existed well before Java ever existed.

The Java Interface construct was created to aid in this idea (among other things), and people have become too focused on the construct as the centre of the meaning rather than the original intent. However, it is the reason we have public and private methods and attributes in Java, C++, C#, etc.

It means just interact with an object or system's public interface. Don't worry or even anticipate how it does what it does internally. Don't worry about how it is implemented. In object-oriented code, it is why we have public vs. private methods/attributes. We are intended to use the public methods because the private methods are there only for use internally, within the class. They make up the implementation of the class and can be changed as required without changing the public interface. Assume that regarding functionality, a method on a class will perform the same operation with the same expected result every time you call it with the same parameters. It allows the author to change how the class works, its implementation, without breaking how people interact with it.

And you can program to the interface, not the implementation without ever using an Interface construct. You can program to the interface not the implementation in C++, which does not have an Interface construct. You can integrate two massive enterprise systems much more robustly as long as they interact through public interfaces (contracts) rather than calling methods on objects internal to the systems. The interfaces are expected to always react the same expected way given the same input parameters; if implemented to the interface and not the implementation. The concept works in many places.

Shake the thought that Java Interfaces have anything what-so-ever to do with the concept of 'Program to the Interface, Not the Implementation'. They can help apply the concept, but they are not the concept.

无法言说的痛 2025-02-10 11:24:57

听起来您了解接口的工作原理,但不确定何时使用它们以及它们提供的优势。以下是何时有意义的一些示例:

// if I want to add search capabilities to my application and support multiple search
// engines such as Google, Yahoo, Live, etc.

interface ISearchProvider
{
    string Search(string keywords);
}

然后,我可以创建GoogleSearchProvider,YahoosearchProvider,LivesearchProvider等。

// if I want to support multiple downloads using different protocols
// HTTP, HTTPS, FTP, FTPS, etc.
interface IUrlDownload
{
    void Download(string url)
}

// how about an image loader for different kinds of images JPG, GIF, PNG, etc.
interface IImageLoader
{
    Bitmap LoadImage(string filename)
}

然后创建Jpegimageloader,Gifimageloader,Pngimageloader等。

大多数添加程序和插件系统都可以与Interfaces脱离接口。

另一个流行的用途是用于存储库模式。假设我想从不同来源加载邮政编码列表

interface IZipCodeRepository
{
    IList<ZipCode> GetZipCodes(string state);
}

,然后我可以创建一个XMLZIPCODEREPOSITOR,SQLZIPCODEREPOSITORITORITY,CSVZIPCODEREPOSITORITORITY等。对于我的Web应用程序,我经常在早期创建XML存储库,以便在SQL Datagabase之前创建XML存储库准备好了。准备好数据库后,我写了一个SQLRepository来替换XML版本。我的其余代码完全不变,因为它仅在接口上运行。

方法可以接受诸如:

PrintZipCodes(IZipCodeRepository zipCodeRepository, string state)
{
    foreach (ZipCode zipCode in zipCodeRepository.GetZipCodes(state))
    {
        Console.WriteLine(zipCode.ToString());
    }
}

It sounds like you understand how interfaces work but are unsure of when to use them and what advantages they offer. Here are a few examples of when an interface would make sense:

// if I want to add search capabilities to my application and support multiple search
// engines such as Google, Yahoo, Live, etc.

interface ISearchProvider
{
    string Search(string keywords);
}

then I could create GoogleSearchProvider, YahooSearchProvider, LiveSearchProvider, etc.

// if I want to support multiple downloads using different protocols
// HTTP, HTTPS, FTP, FTPS, etc.
interface IUrlDownload
{
    void Download(string url)
}

// how about an image loader for different kinds of images JPG, GIF, PNG, etc.
interface IImageLoader
{
    Bitmap LoadImage(string filename)
}

then create JpegImageLoader, GifImageLoader, PngImageLoader, etc.

Most add-ins and plugin systems work off interfaces.

Another popular use is for the Repository pattern. Say I want to load a list of zip codes from different sources

interface IZipCodeRepository
{
    IList<ZipCode> GetZipCodes(string state);
}

then I could create an XMLZipCodeRepository, SQLZipCodeRepository, CSVZipCodeRepository, etc. For my web applications, I often create XML repositories early on so I can get something up and running before the SQL Database is ready. Once the database is ready I write an SQLRepository to replace the XML version. The rest of my code remains unchanged since it runs solely off of interfaces.

Methods can accept interfaces such as:

PrintZipCodes(IZipCodeRepository zipCodeRepository, string state)
{
    foreach (ZipCode zipCode in zipCodeRepository.GetZipCodes(state))
    {
        Console.WriteLine(zipCode.ToString());
    }
}
欢你一世 2025-02-10 11:24:57

那里有很多解释,但是要使它更简单。以 list 为例。一个人可以通过以下列表来实现以下列表:

  1. 内部数组
  2. 通过
  3. 其他实现

构建到接口,例如 list 来实现 。您仅代码列表的定义或 list 实际上意味着什么。

您可以在内部使用任何类型的实现,表示数组实现。但是,假设您希望出于某种原因更改实现,说一个错误或性能。然后,您只需要更改声明 list&lt; string&gt; ls = new arraylist&lt; string&gt;() to list&lt; string&gt; ls = new linkedlist&lt; string&gt;()

在代码中,其他任何地方都没有其他任何内容;因为其他所有内容都是基于 list 的定义。

A lot of explanation out there, but to make it even more simpler. Take for instance a List. One can implement a list with as:

  1. An internal array
  2. A linked list
  3. Other implementations

By building to an interface, say a List. You only code as to definition of List or what List means in reality.

You could use any type of implementation internally say an array implementation. But suppose you wish to change the implementation for some reason say a bug or performance. Then you just have to change the declaration List<String> ls = new ArrayList<String>() to List<String> ls = new LinkedList<String>().

Nowhere else in code, will you have to change anything else; Because everything else was built on the definition of List.

会发光的星星闪亮亮i 2025-02-10 11:24:57

当您拥有一组类似的类时,它使您的代码更加可扩展和更易于维护。我是初级程序员,所以我不是专家,但是我刚刚完成了一个需要类似内容的项目。

我处理与运行医疗设备的服务器对话的客户端软件。我们正在开发此设备的新版本,该版本具有一些新组件,有时必须配置这些组件。新组件有两种类型,它们不同,但是它们也非常相似。基本上,我必须创建两个配置表单,两个列表类,两个类别。

我认为最好为每种控制类型创建一个抽象基类,该类型几乎可以容纳所有真实的逻辑,然后派生的类型来照顾两个组件之间的差异。但是,如果我不得不一直担心类型(嗯,它们可能会有,但是在每种方法中都会有一个“ if”语句或切换),基本类将无法对这些组件进行操作。

我为这些组件定义了一个简单的接口,所有基类都与此接口进行了交谈。现在,当我更改某些内容时,它几乎到处都可以“工作”,而且我没有代码重复。

It makes your code a lot more extensible and easier to maintain when you have sets of similar classes. I am a junior programmer, so I am no expert, but I just finished a project that required something similar.

I work on client side software that talks to a server running a medical device. We are developing a new version of this device that has some new components that the customer must configure at times. There are two types of new components, and they are different, but they are also very similar. Basically, I had to create two config forms, two lists classes, two of everything.

I decided that it would be best to create an abstract base class for each control type that would hold almost all of the real logic, and then derived types to take care of the differences between the two components. However, the base classes would not have been able to perform operations on these components if I had to worry about types all of the time (well, they could have, but there would have been an "if" statement or switch in every method).

I defined a simple interface for these components and all of the base classes talk to this interface. Now when I change something, it pretty much 'just works' everywhere and I have no code duplication.

快乐很简单 2025-02-10 11:24:57

如果您在Java进行编程,JDBC就是一个很好的例子。 JDBC定义了一组接口,但没有说明实现。您的应用程序可以用这组接口编写。从理论上讲,您选择了一些JDBC驱动程序,而您的应用程序只能使用。如果您发现有更快或“更好”或更便宜的JDBC驱动程序或出于任何原因,理论上您可以再次对您的属性文件进行重新配置,而无需对应用程序进行任何更改,则您的应用程序仍然可以正常工作。

If you program in Java, JDBC is a good example. JDBC defines a set of interfaces but says nothing about the implementation. Your applications can be written against this set of interfaces. In theory, you pick some JDBC driver and your application would just work. If you discover there's a faster or "better" or cheaper JDBC driver or for whatever reason, you can again in theory re-configure your property file, and without having to make any change in your application, your application would still work.

£冰雨忧蓝° 2025-02-10 11:24:57

我是这个问题的晚期,但我想在这里提到“界面的程序,而不是实现”行在GOF(四个)设计模式书中进行了一些很好的讨论。

它在p上说。 18:

程序到接口,而不是实现

不要将变量声明为特定混凝土类的实例。相反,仅对由抽象类定义的接口提交。您会发现这是本书设计模式的共同主题。

首先,它始于:

仅根据抽象类定义的接口来操纵对象有两个好处:

  1. 客户仍然不知道其使用的特定对象,只要对象遵守客户端的界面。
  2. 客户仍然不知道实现这些对象的类。客户只知道定义接口的抽象类。

因此,换句话说,请勿写它的类对于特定的类(或子类)的特定实现而言太具体了。相反,使用足够通用的名称编写该方法,例如 gissound() move(),以便它们可以用于鸭子,狗甚至是汽车,然后您的类客户只能说 .givesound(),而不是考虑是否使用 quack() bark(),甚至在发出要发送到对象的正确消息之前确定类型。

I am a late comer to this question, but I want to mention here that the line "Program to an interface, not an implementation" had some good discussion in the GoF (Gang of Four) Design Patterns book.

It stated, on p. 18:

Program to an interface, not an implementation

Don't declare variables to be instances of particular concrete classes. Instead, commit only to an interface defined by an abstract class. You will find this to be a common theme of the design patterns in this book.

and above that, it began with:

There are two benefits to manipulating objects solely in terms of the interface defined by abstract classes:

  1. Clients remain unaware of the specific types of objects they use, as long as the objects adhere to the interface that clients expect.
  2. Clients remain unaware of the classes that implement these objects. Clients only know about the abstract class(es) defining the interface.

So in other words, don't write it your classes so that it has a quack() method for ducks, and then a bark() method for dogs, because they are too specific for a particular implementation of a class (or subclass). Instead, write the method using names that are general enough to be used in the base class, such as giveSound() or move(), so that they can be used for ducks, dogs, or even cars, and then the client of your classes can just say .giveSound() rather than thinking about whether to use quack() or bark() or even determine the type before issuing the correct message to be sent to the object.

墨小墨 2025-02-10 11:24:57

到界面的编程非常棒,它可以促进松散的耦合。正如@lassevk所述,控制反转是对此的极大用途。

此外,还要研究固体主体这是一个视频系列

它通过一个硬编码(强烈耦合示例)然后看起来在接口,最终发展到IOC/DI工具(ninject)

Programming to Interfaces is awesome, it promotes loose coupling. As @lassevk mentioned, Inversion of Control is a great use of this.

In addition, look into SOLID principals. here is a video series

It goes through a hard coded (strongly coupled example) then looks at interfaces, finally progressing to a IoC/DI tool (NInject)

送舟行 2025-02-10 11:24:57

为了添加现有帖子,有时在开发人员同时在单独的组件上工作时,对接口进行编码有助于大型项目。您需要的只是预先定义接口并向它们编写代码,而其他开发人员将代码写入您正在实现的接口。

To add to the existing posts, sometimes coding to interfaces helps on large projects when developers work on separate components simultaneously. All you need is to define interfaces upfront and write code to them while other developers write code to the interface you are implementing.

蓝梦月影 2025-02-10 11:24:57

即使我们不依赖抽象的不同,它也可能有利于编程到接口。

界面的编程迫使我们使用对象的上下文适当子集。这是有帮助的,因为它是:

  1. 防止我们做上下文不适当的事情,并
  2. 让我们将来安全地改变实现。

例如,请考虑实现 friend 员工接口的 person 类。

class Person implements AbstractEmployee, AbstractFriend {
}

在该人的生日的上下文中,我们将其编程到 friend 接口,以防止将其视为雇员

function party() {
    const friend: Friend = new Person("Kathryn");
    friend.HaveFun();
}

在人的工作中,我们将编程为雇员接口,以防止工作场所的模糊界限。

function workplace() {
    const employee: Employee = new Person("Kathryn");
    employee.DoWork();
}

伟大的。我们在不同的情况下表现得很适当,我们的软件运行良好。

到未来,如果我们的业务改变与狗一起工作,我们可以很容易地更改软件。首先,我们创建一个 dog 类,同时实现 friend 员工。然后,我们将 new Person()将其安全地更改为 new Dog()。即使两个函数都有数千行代码,该简单的编辑也会起作用,因为我们知道以下内容是正确的:

  1. 函数 party 仅使用 friend> friend 的子集
  2. 函数工作场所仅使用员工 Person 的子集。
  3. dog 同时实现了 friend 员工接口。

另一方面,如果 party 工作场所是针对 person 进行编程 - 特定代码。从更改 dog 将要求我们梳理代码以消除任何 person - 特定的代码 dog> dog 不支持。

道德:与接口进行编程有助于我们的代码适当地表现并准备好进行更改。它还准备我们的代码取决于抽象,这带来了更多的优势。

It can be advantageous to program to interfaces, even when we are not depending on abstractions.

Programming to interfaces forces us to use a contextually appropriate subset of an object. That helps because it:

  1. prevents us from doing contextually inappropriate things, and
  2. lets us safely change the implementation in the future.

For example, consider a Person class that implements the Friend and the Employee interface.

class Person implements AbstractEmployee, AbstractFriend {
}

In the context of the person's birthday, we program to the Friend interface, to prevent treating the person like an Employee.

function party() {
    const friend: Friend = new Person("Kathryn");
    friend.HaveFun();
}

In the context of the person's work, we program to the Employee interface, to prevent blurring workplace boundaries.

function workplace() {
    const employee: Employee = new Person("Kathryn");
    employee.DoWork();
}

Great. We have behaved appropriately in different contexts, and our software is working well.

Far into the future, if our business changes to work with dogs, we can change the software fairly easily. First, we create a Dog class that implements both Friend and Employee. Then, we safely change new Person() to new Dog(). Even if both functions have thousands of lines of code, that simple edit will work because we know the following are true:

  1. Function party uses only the Friend subset of Person.
  2. Function workplace uses only the Employee subset of Person.
  3. Class Dog implements both the Friend and Employee interfaces.

On the other hand, if either party or workplace were to have programmed against Person, there would be a risk of both having Person-specific code. Changing from Person to Dog would require us to comb through the code to extirpate any Person-specific code that Dog does not support.

The moral: programming to interfaces helps our code to behave appropriately and to be ready for change. It also prepares our code to depend on abstractions, which brings even more advantages.

眼眸里的那抹悲凉 2025-02-10 11:24:57

如果我正在写新类游泳者添加功能 swim(),并且需要使用类SAIS SAID Dog 的对象,这类实现接口<代码>动物声明 swim> swim>

在层次结构的顶部( Animal ),在底部( dog )时非常抽象,这是非常具体的。我对“与接口进行编程”的看法是,当我编写游泳器类时,我想针对界面编写代码动物对象。接口没有实现详细信息,因此使您的代码松散地耦合。

可以随时间更改实现详细信息,但是,由于您与接口而不是实现相互作用,它不会影响剩余的代码。您不在乎实现是什么样的...您所知道的是,将有一个可以实现界面的类。

If I'm writing a new class Swimmer to add the functionality swim() and need to use an object of class say Dog, and this Dog class implements interface Animal which declares swim().

At the top of the hierarchy (Animal), it's very abstract while at the bottom (Dog) it's very concrete. The way I think about "programming to interfaces" is that, as I write Swimmer class, I want to write my code against the interface that's as far up that hierarchy which in this case is an Animal object. An interface is free from implementation details and thus makes your code loosely-coupled.

The implementation details can be changed with time, however, it would not affect the remaining code since all you are interacting with is with the interface and not the implementation. You don't care what the implementation is like... all you know is that there will be a class that would implement the interface.

口干舌燥 2025-02-10 11:24:57

先前的答案集中在编程上,以进行抽象,以扩展性和松散的耦合。虽然这些是非常重要的一点
可读性同样重要。可读性使他人(和您的未来自我)可以最少的精力理解代码。这就是为什么可读性利用抽象的原因。

从定义上讲,抽象比其实现更简单。抽象省略了细节,以传达事物的本质或目的,但仅此而已。
由于抽象更简单,因此与实施相比,我一次可以将更多的内容放在脑海中。

作为程序员(以任何语言),我始终在我的脑海中走动 list 的一般想法。特别是, list 允许随机访问,重复元素并维护顺序。当我看到这样的声明时: list mylist = new Arraylist()我认为, cool ,这是 list 在(基本)我理解的方式;而且我不必再考虑它了。

另一方面,我脑海中没有携带 arrayList 的特定实现详细信息。因此,当我看到时, arrayList myList = new ArrayList()。我认为, uh-oh ,必须以 list> list 接口不介绍的方式使用此 arraylist 。现在,我必须跟踪此 arrayList 的所有用法,以了解原因,因为否则我将无法完全理解此代码。当我发现此 arraylist do 符合 list> list 接口的100%用法时,它会变得更加令人困惑。然后我想知道...是否有一些代码依赖于 arraylist 实现详细信息?实例化的程序员是无能的吗?该应用程序是否在运行时以某种方式锁定到该特定实现中?我不明白的方式?

我现在对此应用程序感到困惑和不确定,而我们所谈论的只是一个简单的 list 。如果这是一个复杂的业务对象,忽略其界面怎么办?然后,我对业务领域的了解不足以了解代码的目的。

因此,即使我需要一个 list 严格在私有方法中(如果更改的情况下,什么都不会破坏其他应用程序,我可以轻松地找到/替换我的IDE中的所有用法)它仍然有利于编程进行抽象的可读性。因为抽象比实施细节更简单。您可以说,编程到抽象是遵守 kiss 原则的一种方式。

Previous answers focus on programming to an abstraction for the sake of extensibility and loose coupling. While these are very important points,
readability is equally important. Readability allows others (and your future self) to understand the code with minimal effort. This is why readability leverages abstractions.

An abstraction is, by definition, simpler than its implementation. An abstraction omits detail in order to convey the essence or purpose of a thing, but nothing more.
Because abstractions are simpler, I can fit a lot more of them in my head at one time, compared to implementations.

As a programmer (in any language) I walk around with a general idea of a List in my head at all times. In particular, a List allows random access, duplicate elements, and maintains order. When I see a declaration like this: List myList = new ArrayList() I think, cool, this is a List that's being used in the (basic) way that I understand; and I don't have to think any more about it.

On the other hand, I do not carry around the specific implementation details of ArrayList in my head. So when I see, ArrayList myList = new ArrayList(). I think, uh-oh, this ArrayList must be used in a way that isn't covered by the List interface. Now I have to track down all the usages of this ArrayList to understand why, because otherwise I won't be able to fully understand this code. It gets even more confusing when I discover that 100% of the usages of this ArrayList do conform to the List interface. Then I'm left wondering... was there some code relying on ArrayList implementation details that got deleted? Was the programmer who instantiated it just incompetent? Is this application locked into that specific implementation in some way at runtime? A way that I don't understand?

I'm now confused and uncertain about this application, and all we're talking about is a simple List. What if this was a complex business object ignoring its interface? Then my knowledge of the business domain is insufficient to understand the purpose of the code.

So even when I need a List strictly within a private method (nothing that would break other applications if it changed, and I could easily find/replace every usage in my IDE) it still benefits readability to program to an abstraction. Because abstractions are simpler than implementation details. You could say that programming to abstractions is one way of adhering to the KISS principle.

玉环 2025-02-10 11:24:57

它也适合单位测试,您可以将自己的类(满足界面的要求)注入依赖于此的类

It is also good for Unit Testing, you can inject your own classes (that meet the requirements of the interface) into a class that depends on it

帥小哥 2025-02-10 11:24:57

短篇小说:邮递员被要求回家后回家,并收到包含的封面(信件,文件,支票,礼品卡,申请,情书),并在其上写的地址交付。

假设没有掩护,请邮递员在回家后回家,收到所有的东西并交付给其他人,邮递员会感到困惑。

因此,更好地用封面包裹它(在我们的故事中是界面),然后他会做得很好。

现在,邮递员的工作是只接收和交付封面(他不会打扰封面中的内部)。

创建一种类型的接口不是实际类型,而是使用实际类型来实现它。

要创建界面,意味着您的组件可以轻松地融入其余代码

我给您一个例子。

您的飞机接口如下。

interface Airplane{
    parkPlane();
    servicePlane();
}

假设您在程序中的控制器类别中具有方法,例如

parkPlane(Airplane plane)

servicePlane(Airplane plane)

程序中实现。它不会中断您的代码。
我的意思是,只要它接受飞机的参数,就不必更改。

因为尽管实际类型, highflyr ,战斗机等,但它仍将接受任何

飞机

。飞机&gt;飞机; //将占用所有飞机。

以下示例将清除您的理解。


您有一架实施它的战斗机,因此

public class Fighter implements Airplane {

    public void  parkPlane(){
        // Specific implementations for fighter plane to park
    }
    public void  servicePlane(){
        // Specific implementatoins for fighter plane to service.
    }
}

对于HighFlyer和其他Clasess来说,相同的东西:

public class HighFlyer implements Airplane {

    public void  parkPlane(){
        // Specific implementations for HighFlyer plane to park
    }

    public void  servicePlane(){
        // specific implementatoins for HighFlyer plane to service.
    }
}

几次使用飞机的控制器类,

假设您的控制器类是控制页面的,如下

public Class ControlPlane{ 
 AirPlane plane;
 // so much method with AirPlane reference are used here...
}

现在 可能会使您的新飞机按照您想要的数量输入实例,并且您没有更改 Control Plane Plane 类的代码。

您可以添加一个实例...

JumboJetPlane // implementing AirPlane interface.
AirBus        // implementing AirPlane interface.

您也可以删除先前创建类型的实例。

Short story: A postman is asked to go home after home and receive the covers contains (letters, documents, cheques, gift cards, application, love letter) with the address written on it to deliver.

Suppose there is no cover and ask the postman to go home after home and receive all the things and deliver to other people, the postman can get confused.

So better wrap it with cover (in our story it is the interface) then he will do his job fine.

Now the postman's job is to receive and deliver the covers only (he wouldn't bothered what is inside in the cover).

Create a type of interface not actual type, but implement it with actual type.

To create to interface means your components get Fit into the rest of code easily

I give you an example.

you have the AirPlane interface as below.

interface Airplane{
    parkPlane();
    servicePlane();
}

Suppose you have methods in your Controller class of Planes like

parkPlane(Airplane plane)

and

servicePlane(Airplane plane)

implemented in your program. It will not BREAK your code.
I mean, it need not to change as long as it accepts arguments as AirPlane.

Because it will accept any Airplane despite actual type, flyer, highflyr, fighter, etc.

Also, in a collection:

List<Airplane> plane; // Will take all your planes.

The following example will clear your understanding.


You have a fighter plane that implements it, so

public class Fighter implements Airplane {

    public void  parkPlane(){
        // Specific implementations for fighter plane to park
    }
    public void  servicePlane(){
        // Specific implementatoins for fighter plane to service.
    }
}

The same thing for HighFlyer and other clasess:

public class HighFlyer implements Airplane {

    public void  parkPlane(){
        // Specific implementations for HighFlyer plane to park
    }

    public void  servicePlane(){
        // specific implementatoins for HighFlyer plane to service.
    }
}

Now think your controller classes using AirPlane several times,

Suppose your Controller class is ControlPlane like below,

public Class ControlPlane{ 
 AirPlane plane;
 // so much method with AirPlane reference are used here...
}

Here magic comes as you may make your new AirPlane type instances as many as you want and you are not changing the code of ControlPlane class.

You can add an instance...

JumboJetPlane // implementing AirPlane interface.
AirBus        // implementing AirPlane interface.

You may remove instances of previously created types too.

爱给你人给你 2025-02-10 11:24:57

因此,仅仅为了正确处理这个问题,接口的优点是我可以将方法的调用与任何特定类别分开。而是创建一个接口的实例,其中从我选择该界面的任何类中给出了实现。因此,我可以拥有许多类,这些类具有相似但略有不同的功能,在某些情况下(与界面的意图相关的情况)并不关心它是哪个对象。

例如,我可以有一个运动接口。一种使某物“移动”的方法和实现移动接口的任何对象(人,汽车,猫)都可以传递并被告知要移动。没有方法,每个都知道它的类型。

So, just to get this right, the advantage of a interface is that I can separate the calling of a method from any particular class. Instead creating a instance of the interface, where the implementation is given from whichever class I choose that implements that interface. Thus allowing me to have many classes, which have similar but slightly different functionality and in some cases (the cases related to the intention of the interface) not care which object it is.

For example, I could have a movement interface. A method which makes something 'move' and any object (Person, Car, Cat) that implements the movement interface could be passed in and told to move. Without the method every knowing the type of class it is.

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