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