当前位置:  开发笔记 > 编程语言 > 正文

编程到接口是什么意思?

如何解决《编程到接口是什么意思?》经验,为你挑选了5个好方法。

我一直听到大多数与节目相关的网站上的声明:

编程到接口而不是实现

但是我不明白其含义?
例子会有所帮助.

编辑:我收到了很多好的答案,所以你可以用一些代码片段来补充它,以便更好地理解这个主题.谢谢!



1> weiji..:

你可能正在寻找这样的东西:

public static void main(String... args) {
  // do this - declare the variable to be of type Set, which is an interface
  Set buddies = new HashSet();

  // don't do this - you declare the variable to have a fixed type
  HashSet buddies2 = new HashSet();
}

为什么第一种方式做到这一点感觉很好?我们稍后会说你决定使用不同的数据结构,比如LinkedHashSet,以便利用LinkedHashSet的功能.代码必须像这样改变:

public static void main(String... args) {
  // do this - declare the variable to be of type Set, which is an interface
  Set buddies = new LinkedHashSet();  // <- change the constructor call

  // don't do this - you declare the variable to have a fixed type
  // this you have to change both the variable type and the constructor call
  // HashSet buddies2 = new HashSet();  // old version
  LinkedHashSet buddies2 = new LinkedHashSet();
 }

这看起来不是那么糟糕吧?但是如果你用同样的方式写getter怎么办?

public HashSet getBuddies() {
  return buddies;
}

这也必须改变!

public LinkedHashSet getBuddies() {
  return buddies;
}

希望您看到,即使使用这样的小程序,您对声明变量类型的内容也会产生深远的影响.如果你只是依赖于一个被声明为接口的变量,而不是作为该接口的特定实现(在这种情况下,声明它是一个接口),那么对象来回这么多肯定有助于使程序更容易编码和维护设置,而不是LinkedHashSet或其他).它可以是这样的:

public Set getBuddies() {
  return buddies;
}

还有另外一个好处,那个(至少对我而言)差异有助于我更好地设计一个程序.但希望我的例子给你一些想法...希望它有所帮助.


关于为代码过度使用这个原则要非常小心.如果每类有被定义相应的接口,总是有THES类和接口之间的1对1的对应关系,那么它只是用来混淆代码,并使其难以维持.知道什么时候引入接口因为您将来想要引入不同的实现是关键.
请记住,这个原则适用于您创建的类型以及Set之类的内置抽象.例如,如果项目中有"Foo".不要只是做一个"类Foo,"反而让"界面富",然后有一些像执行"类MyFoo实现富"你甚至可能会发现,你的项目将有实现的"富"界面几类.通过一致地编写接口的名称而不是实现(构造函数调用除外),您可以快速更改Foo实现以满足您的需求.
我真的不喜欢这个关于声明局部变量的标准示例.这是一个非常弱的接口案例.方法参数是一个更强大的案例 - 声明一个HashSet参数,并强制客户端使用HashSet.声明一个Set参数,他们可以自由使用Collections.singleton(),Collections.emptySet()或他们自己的自定义Set实现.

2> Wim Coenen..:

有一天,他的老板指示一名初级程序员编写一份应用程序来分析业务数据,并将其全部压缩在包含指标,图表和所有内容的漂亮报告中.老板给了他一个XML文件,上面写着"这是一些商业数据示例".

程序员开始编码.几个星期后,他觉得指标,图表和东西足以让老板满意,并且他展示了他的作品."这太棒了"老板说,"但是它还可以显示我们拥有的SQL数据库的商业数据吗?".

程序员回到编码.在他的应用程序中,有从XML中读取业务数据的代码.他重写了所有这些片段,用"if"条件包装它们:

if (dataType == "XML")
{
   ... read a piece of XML data ...
}
else
{
   .. query something from the SQL database ...
}

当出现软件的新版本时,老板回答说:"这很好,但它是否也能报告来自这个Web服务的业务数据?" 记住所有那些乏味的陈述,他必须重写AGAIN,程序员变得愤怒."首先是xml,然后是SQL,现在是Web服务!什么是真正的业务数据来源?"

老板回答说:"任何可以提供它的东西"

那一刻,程序员开悟了.


他意识到,通过针对数据源的单一抽象进行编程,他可以使大多数代码与数据源的类型无关; 一个界面!添加对新数据源类型的支持就变成了创建接口的新实现的问题.其余的代码不必触及.这是**数据映射器**模式.

3> rmeador..:

我对该陈述的初步阅读与我读过的任何答案都非常不同.我同意所有使用接口类型为你的方法参数的人都非常重要,但这不是这个陈述对我意味着什么.

我的看法是,它告诉你编写的代码只取决于你正在使用的接口(在这种情况下,我使用"接口"来表示类或接口类型的公开方法),它在文档.这与编写代码相反,代码取决于您调用的函数的实现细节.您应该将所有函数调用视为黑盒子(如果两个函数都是同一类的方法,则可以对此进行例外处理,但理想情况下,它始终保持不变).

示例:假设有一个ScreenDraw(image)Clear()方法.文档说的是"draw方法在屏幕上绘制指定的图像"和"clear方法清除屏幕".如果要按顺序显示图像,正确的方法是重复调用,Clear()然后按Draw().这将编码到界面.如果您正在编写实现代码,那么您可能会执行类似于调用Draw()方法的操作,因为您在进行任何绘制之前通过查看Draw()内部调用的实现来了解Clear().这很糟糕,因为您现在依赖于通过查看公开的界面无法了解的实现细节.

我期待看到是否有其他人在OP的问题中分享这句话的解释,或者如果我完全偏离基础......


这也是我的理解 - 对接口的编程意味着编程到文档,规范或协议.因此,如果您正在编程接口,关于"X工作"的讨论不是"我试过它并且它工作/不起作用",它更像是"我阅读文档,它允许X /禁止X /未提及X /对X"不明确".

4> mjv..:

这是一种在模块之间分离职责/依赖性的方法.通过定义特定的接口(API),可以确保接口任一侧的模块不会互相"打扰".

例如,假设模块1将负责显示特定用户的银行账户信息,而模块2将从"使用"后端获取银行账户信息.

通过定义一些类型和函数,以及相关参数,例如定义银行交易的结构,以及一些方法(函数),如GetLastTransactions(AccountNumber,NbTransactionsWanted,ArrayToReturnTheseRec)和GetBalance(AccountNumer),Module1将能够获取所需信息,而不用担心如何存储或计算此信息或其他任何信息.相反,Module2将通过按照定义的界面提供信息来响应方法调用,但不会担心显示,打印或其他任何信息的位置......

当模块改变时,接口的实现可能会有所不同,但只要接口保持不变,使用API​​的模块最坏的情况可能需要重新编译/重建,但它们不需要修改其逻辑.无论如何.

这就是API的想法.



5> OscarRyz..:

接口定义了提交响应对象的方法.

当你的代码的接口,你可以改变的基础对象和你的代码仍然可以工作(因为你的代码是不可知的谁做执行任务或如何进行工作)你获得的灵活性这样.

当您对特定实现进行编码时,如果需要更改底层对象,则代码很可能会中断,因为新对象可能无法响应相同的方法.

所以举一个明显的例子:

如果您需要持有许多对象,则可能已决定使用Vector.

如果您需要访问Vector的第一个对象,您可以编写:

 Vector items = new Vector(); 
 // fill it 
 Object first = items.firstElement();

到现在为止还挺好.

后来你决定,因为"某种"原因你需要改变实现(假设Vector因过度同步而产生瓶颈)

您意识到需要使用ArrayList instad.

好吧,你的代码会破...

ArrayList items = new ArrayList();
// fill it  
Object first = items.firstElement(); // compile time error. 

你不能.这一行以及使用firstElement()方法的所有行都会中断.

如果你需要特定的行为,你肯定需要这个方法,它可能没问题(虽然你将无法改变实现) 但是如果你需要的是简单地检索第一个元素(也就是说,没有什么特别的其他具有firstElement()方法的Vector然后使用接口而不是实现将为您提供更改的灵活性.

 List items = new Vector();
 // fill it 
 Object first = items.get( 0 ); //

在这种形式中,您不是编码为Vector的get方法,而是编写List的get方法.

底层对象如何执行该方法无关紧要,只要它响应"获取集合的第0个元素"的契约即可

这样您以后可以将其更改为任何其他实现:

 List items = new ArrayList(); // Or LinkedList or any other who implements List
 // fill it 
 Object first = items.get( 0 ); // Doesn't break

这个示例可能看起来很幼稚,但它是OO技术所依据的基础(即使是那些非静态类型的语言,如Python,Ruby,Smalltalk,Objective-C等)

一个更复杂的例子是JDBC的工作方式.您可以更改驱动程序,但大多数调用都将以相同的方式工作.例如,您可以使用oracle数据库的标准驱动程序,或者您可以使用Weblogic或Webpshere提供的更复杂的驱动程序.当然,你以前仍然需要测试你的产品并不神奇,但至少你没有像以下那样的东西:

 statement.executeOracle9iSomething();

VS

statement.executeOracle11gSomething();

Java Swing也发生了类似的事情.

补充阅读:

设计模式的设计原则

有效Java项:通过其接口引用对象

(购买这本书是你在生活中可以做的最好的事情之一 - 当然,请阅读 - )

推荐阅读
和谐啄木鸟
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有