我希望巩固我对“编码到界面”概念的理解。据我所知,一个人创建界面来描述预期的功能,然后在具体的类中实现这些“契约”。要使用接口,可以简单地在具体类的实例上调用方法。
明显的好处是了解具体类提供的功能,而不管其具体实现如何。
基于以上所述:
感谢。
答案 0 :(得分:15)
只有一个可能的更正:
要使用接口,可以简单地在具体类的实例上调用方法。
可以在类型接口的引用上调用方法,这恰好使用具体类作为实现:
List<String> l = new ArrayList<String>();
l.add("foo");
l.add("bar");
如果您决定切换到另一个List实现,则客户端代码无需更改即可运行:
List<String> l = new LinkedList<String>();
这对于隐藏实现细节,自动生成代理等特别有用。
您会发现像spring和guice这样的框架鼓励对界面进行编程。它是aspect-oriented编程,自动生成的事务管理代理等想法的基础。
答案 1 :(得分:5)
您的理解似乎正确。你的同事只是摆在你的办公桌旁,并把你喝醉了的老板主演的圣诞派对的所有最新照片装到他的拇指驱动器上。你的同事和你没有想过这个拇指驱动器是如何工作的,对你来说它是一个黑盒子,但你知道它可以工作,因为 USB接口。
无论是SanDisk还是Titanium(甚至不确定是品牌)都没关系,尺寸/颜色也无关紧要。事实上,唯一重要的是它没有被破坏(可读)并且它插入USB。
你的USB拇指驱动器遵守合同,它本质上是一个接口。人们可以认为它履行了一些非常基本的职责:
遵守合约方法CopyDataTo:
公共接口IUSB { void CopyDataTo(string somePath); //用于将数据从缩略图驱动器复制到... }
遵守合约方法CopyDataFrom:
公共接口IUSB { void CopyDataFrom(); //用于将数据从PC复制到缩略图驱动器 }
好吧也许不是那些方法,但 IUSB 界面只是缩略图驱动器供应商必须遵守的合同,以确保跨各种平台/供应商的功能。所以SanDisk通过界面制作了他们的拇指驱动器:
public class SanDiskUSB : IUSB
{
//todo: define methods of the interface here
}
Ari,我认为你已经对界面如何运作有了深刻的理解(听起来是什么样的)。
答案 2 :(得分:4)
主要优点是使用接口将类与其依赖关系松散地耦合。然后,您可以更改类,或实现新的具体接口实现,而无需更改依赖于它的类。
答案 3 :(得分:4)
要使用接口,可以简单地在具体类的实例上调用方法。
通常,您将为接口类型键入一个变量,从而只允许访问接口中定义的方法。
显而易见的好处是了解具体类提供的功能,无论其具体实现如何。
排序。最重要的是,它允许您编写带有接口类型参数的API。然后,API的用户可以传入他们自己的类(实现这些接口),并且您的代码将在这些类上工作,即使它们在编写时尚不存在(例如java.util.Arrays.sort()能够对实现Comparable
或带有合适的Comparator
的任何内容进行排序。
从设计角度来看,接口允许/强制明确区分API合同和实现细节。
答案 4 :(得分:2)
对接口进行编码的目的是将代码与正在使用的具体实现分离。也就是说,您的代码不会假设具体类型,只有接口。因此,无需调整代码即可交换具体实现。
答案 5 :(得分:1)
您没有列出有关如何获得接口实现的部分,这很重要。如果使用构造函数显式实例化实现类,那么您的代码将与该实现相关联。您可以使用工厂为您获取实例,但之后您将像以前一样与实施类绑定。你的第三种选择是使用依赖注入,它将工厂插件实现对象插入到使用它的对象中,在这种情况下,你可以使用绑定到实现类或工厂的对象进行转义。
答案 6 :(得分:0)
我想您可能已经暗示过这一点,但我相信编码接口的最大好处之一就是您打破了对具体实现的依赖。您可以实现松散耦合,并且可以在不更改代码的情况下更轻松地切换特定实现。如果您只是在学习,我会看看各种design patterns以及它们如何通过编码接口来解决问题。阅读这本书Head First: Design Patterns确实有助于我点击。
答案 7 :(得分:0)
据我所知,有人创建界面来描述预期的功能,然后在具体的类中实现这些“契约”。
我在你的想法中看到的唯一一种突变是这样的 - 你将要调出预期的合同,而不是预期的功能。该功能在具体类中实现。接口仅声明您可以使用预期的方法签名调用实现接口的内容。功能对调用对象是隐藏的。
这将允许您将您的想法扩展到多态,如下所示。
SoundMaker sm = new Duck();<br/>
SoundMaker sm1 = new ThunderousCloud();
sm.makeSound(); // quack, calls all sorts of stuff like larynx, etc.<br/>
sm1.makeSound(); // BOOM!, completely different operations here...