Java “编程到接口”。这是什么意思?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1992384/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
"Program to an interface". What does it mean?
提问by gameover
Possible Duplicate:
What does it mean to “program to an interface”?
可能的重复:
“编程到接口”是什么意思?
I keep coming across this term:
我不断遇到这个词:
Program to an interface.
编程到接口。
What exactly does it mean? A real life design scenario would be highly appreciated.
究竟是什么意思?一个现实生活中的设计场景将受到高度赞赏。
采纳答案by Eric King
To put it simply, instead of writing your classes in a way that says
简单地说,而不是用这样的方式编写你的类
I depend on this specificclass to do my work
我依靠这个特定的班级来做我的工作
you write it in a way that says
你写的方式说
I depend on any classthat does this stuffto do my work.
我依靠任何做这些事情的班级来完成我的工作。
The first example represents a class that depends on a specific concrete implementation to do its work. Inherently, that's not very flexible.
第一个示例表示一个类,该类依赖于特定的具体实现来完成其工作。从本质上讲,这不是很灵活。
The second example represents a class written to an interface. It doesn't care what concrete object you use, it just cares that it implements certain behavior. This makes the class much more flexible, as it can be provided with any number of concrete implementations to do its work.
第二个例子代表了一个写到接口的类。它不关心你使用什么具体的对象,它只关心它实现了某些行为。这使得该类更加灵活,因为它可以提供任意数量的具体实现来完成其工作。
As an example, a particular class may need to perform some logging. If you write the class to depend on a TextFileLogger, the class is forever forced to write out its log records to a text file. If you want to change the behavior of the logging, you must change the class itself. The class is tightly coupled with its logger.
例如,一个特定的类可能需要执行一些日志记录。如果您将类编写为依赖于 TextFileLogger,则该类将永远被迫将其日志记录写出到文本文件中。如果要更改日志记录的行为,则必须更改类本身。该类与其记录器紧密耦合。
If, however, you write the class to depend on an ILogger interface, and then provide the class with a TextFileLogger, you will have accomplished the same thing, but with the added benefit of being much more flexible. You are able to provide any other type of ILogger at will, without changing the class itself. The class and its logger are now loosely coupled, and your class is much more flexible.
但是,如果您编写依赖于 ILogger 接口的类,然后为该类提供一个 TextFileLogger,您将完成同样的事情,但额外的好处是更加灵活。您可以随意提供任何其他类型的 ILogger,而无需更改类本身。这个类和它的记录器现在是松散耦合的,你的类更加灵活。
回答by Uri
I think this is one of Erich Gamma's mantras. I can't find the first time he described it (before the GOF book), but you can see it discussed in an interview at: http://www.artima.com/lejava/articles/designprinciples.html
我认为这是 Erich Gamma 的口头禅之一。我找不到他第一次描述它的时间(在 GOF 书之前),但您可以在以下采访中看到它的讨论:http: //www.artima.com/lejava/articles/designprinciples.html
回答by raoulsson
"Programming to an interface" happens when you use libraries, other code you depend upon in your own code. Then, the way that other code represents itself to you, the method names, its parameters, return values etc make up the interfaceyou have to program to. So it's about how you use third-party code.
当您使用库以及您自己的代码中依赖的其他代码时,就会发生“编程接口”。然后,其他代码向您表示自己的方式、方法名称、其参数、返回值等构成了您必须编程的接口。所以它是关于你如何使用第三方代码。
It also means, you don't have to care about the internals of the code you depend on, as long as the interface stays the same, your code is safe (well, more or less...)
这也意味着,您不必关心所依赖代码的内部结构,只要接口保持不变,您的代码就是安全的(好吧,或多或少......)
Technically there are finer details, like language concepts called "interfaces" in Java for example.
从技术上讲,还有更精细的细节,例如 Java 中称为“接口”的语言概念。
If you want to find out more, you could ask what "Implementing an Interface" means...
如果你想了解更多,你可以问“实现接口”是什么意思......
回答by Bozho
Real-world examples are applenty. One of them:
现实世界的例子是苹果。其中之一:
For JDBC, you are using the interface java.sql.Connection
. However, each JDBC driver provides its own implementation of Connection
. You don't have to know anything about the particular implementation, because it conformsto the Connection
interface.
对于 JDBC,您使用的是接口java.sql.Connection
. 但是,每个 JDBC 驱动程序都提供了自己的Connection
. 你不必知道具体的实现什么,因为它符合该Connection
接口。
Another one is from the java collections framework. There is a java.util.Collection
interface, which defines size
, add
and remove
methods (among many others). So you can use all types of collections interchangeably. Let's say you have the following:
另一个来自java集合框架。有一个java.util.Collection
接口,它定义size
,add
和remove
方法(以及许多其他)。因此,您可以互换使用所有类型的集合。假设您有以下内容:
public float calculateCoefficient(Collection collection) {
return collection.size() * something / somethingElse;
}
And two other methods that invoke this one. One of the other methods uses a LinkedList
because it's more efficient for it's purposes, and the other uses a TreeSet
.
以及调用此方法的另外两种方法。其他方法之一使用 a 是LinkedList
因为它的目的更有效,而另一种使用 a TreeSet
。
Because both LinkedList
and TreeSet
implement the Collection
interface, you can use only one method to perform the coefficient calculation. No need to duplicate your code.
因为这两个LinkedList
和TreeSet
实现Collection
接口,可以只使用一种方法来执行系数计算。无需复制您的代码。
And here comes the "program to an interface" - you don't care how exactly is the size()
method implemented, you know that it should return the size of the collection - i.e. you have programmed to the Collection
interface, rather than to LinkedList
and TreeSet
in particular.
而这里来了“节目的接口” -你不在乎究竟是如何的size()
方法来实现,你知道它应该返回集合的大小-也就是你编程的Collection
接口,而不是LinkedList
和TreeSet
特别。
But my advice is to find a reading - perhaps a book ("Thinking in Java" for example) - where the concept is explained in details.
但我的建议是找一本书——也许是一本书(例如“Thinking in Java”)——其中详细解释了这个概念。
回答by Kevin Montrose
Every object has an exposed interface. A collection has Add
, Remove
, At
, etc. A socket may have Send
, Receive
, Close
and so on.
每个对象都有一个公开的接口。集合了Add
,Remove
,At
等套接字可能有Send
,Receive
,Close
等。
Every object you can actually get a reference to has a concrete implementation of these interfaces.
您可以实际获得引用的每个对象都有这些接口的具体实现。
Both of these things are obvious, however what is somewhat less obvious...
这两件事都是显而易见的,但有些不太明显……
Your code shouldn't rely on the implementation details of an object, just its published interface.
您的代码不应依赖于对象的实现细节,而应依赖于其发布的接口。
If you take it to an extreme, you'd only code against Collection<T>
and so on (rather than ArrayList<T>
). More practically, just make sure you could swap in something conceptually identical without breaking your code.
如果你把它带到极端,你只会编码反对Collection<T>
等等(而不是ArrayList<T>
)。更实际的是,只要确保您可以在不破坏代码的情况下交换概念上相同的东西。
To hammer out the Collection<T>
example: you have a collection of something, you're actually using ArrayList<T>
because why not. You should make sure you're code isn't going to break if, say, you end up using LinkedList<T>
in the future.
敲定的Collection<T>
例子:你有东西的集合,你实际使用ArrayList<T>
,因为何乐而不为。你应该确保你的代码不会被破坏,比如,如果你LinkedList<T>
将来最终使用。
回答by Noufal Ibrahim
It basically means that the only part of the library which you're going to use you should rely upon is it's API (Application programming interface) and that you shouldn't base your application on the concrete implementation of the library.
它基本上意味着您将要使用的库中唯一应该依赖的部分是它的 API(应用程序编程接口),并且您不应该将您的应用程序基于库的具体实现。
eg. Supposed you have a library that gives you a stack
. The class gives you a couple of methods. Let's say push
, pop
, isempty
and top
. You should write your application relying only on these. One way to violate this would be to peek inside and find out that the stack is implemented using an array of some kind so that if you pop from an empty stack, you'd get some kind of Index exception and to then catch this rather than to rely on the isempty
method which the class provides. The former approach would fail if the library provider switched from using an array to using some kind of list while the latter would still work assuming that the provider kept his API still working.
例如。假设您有一个库,可以为您提供stack
. 该类为您提供了几种方法。假设push
, pop
,isempty
和top
。你应该只依赖这些来编写你的应用程序。违反这一点的一种方法是查看内部并发现堆栈是使用某种数组实现的,因此如果您从空堆栈中弹出,您会得到某种索引异常,然后捕获它而不是依赖isempty
类提供的方法。如果库提供者从使用数组切换到使用某种列表,则前一种方法将失败,而假设提供者保持其 API 仍然有效,后者仍然可以工作。
回答by Joe Phillips
Polymorphism depends on programming to an interface, not an implementation.
多态依赖于对接口的编程,而不是实现。
There are two benefits to manipulating objects solely in terms of the interface defined by abstract classes:
仅根据抽象类定义的接口来操作对象有两个好处:
- Clients remain unaware of the specific types of objects they use, as long as the objects adhere to the interface that clients expect.
- Clients remain unaware of the classes that implement these objects. Clients only know about the abstract class(es) defining the interface.
- 只要对象遵循客户期望的接口,客户就不会知道他们使用的特定类型的对象。
- 客户端仍然不知道实现这些对象的类。客户端只知道定义接口的抽象类。
This so greatly reduces implementation dependencies between subsystems that it leads to this principle of programming to an interface.
这极大地减少了子系统之间的实现依赖性,从而导致了对接口进行编程的这一原则。
See the Factory Method patternfor further reasoning of this design.
有关此设计的进一步推理,请参阅工厂方法模式。
Source: "Design Patterns: Elements of Reusable Object-Oriented Software" by G.O.F.
来源:GOF 的“设计模式:可重用面向对象软件的元素”
回答by Thomas Zoechling
An interface is a collection of related methods, that only contains the signatures of those methods - not the actual implementation.
If a class implements an interface (class Car implements IDrivable
) it has to provide code for all signatures defined in the interface.
接口是相关方法的集合,只包含这些方法的签名——而不是实际的实现。
如果一个类实现了一个接口 ( class Car implements IDrivable
),它必须为接口中定义的所有签名提供代码。
Basic example:
You have to classes Car and Bike. Both implement the interface IDrivable:
基本示例:
您必须对 Car 和 Bike 进行分类。两者都实现了接口 IDrivable:
interface IDrivable
{
void accelerate();
void brake();
}
class Car implements IDrivable
{
void accelerate()
{ System.out.println("Vroom"); }
void brake()
{ System.out.println("Queeeeek");}
}
class Bike implements IDrivable
{
void accelerate()
{ System.out.println("Rattle, Rattle, ..."); }
void brake()
{ System.out.println("..."); }
}
Now let's assume you have a collection of objects, that are all "drivable" (their classes all implement IDrivable):
现在让我们假设您有一个对象集合,它们都是“可驱动的”(它们的类都实现了 IDrivable):
List<IDrivable> vehicleList = new ArrayList<IDrivable>();
list.add(new Car());
list.add(new Car());
list.add(new Bike());
list.add(new Car());
list.add(new Bike());
list.add(new Bike());
If you now want to loop over that collection, you can rely on the fact, that every object in that collection implements accelerate()
:
如果您现在想要遍历该集合,您可以依赖于该集合中的每个对象都实现accelerate()
:
for(IDrivable vehicle: vehicleList)
{
vehicle.accelerate(); //this could be a bike or a car, or anything that implements IDrivable
}
By calling that interface method you are not programming to an implementation but to an interface - a contract that ensures that the call target implements a certain functionality.
The same behavior could be achieved using inheritance, but deriving from a common base class results in tight coupling which can be avoided using interfaces.
通过调用该接口方法,您不是在对实现进行编程,而是对接口进行编程 - 一种确保调用目标实现特定功能的契约。
使用继承可以实现相同的行为,但是从公共基类派生会导致紧密耦合,而使用接口可以避免这种情况。