Eri*_*ing 76
简单地说,而不是以一种说法来编写你的课程
我依靠这个特定的班级来完成我的工作
你用这样的方式写它
我依靠任何做这些事情的班级来完成我的工作.
第一个示例表示一个类,它依赖于特定的具体实现来完成其工作.从本质上讲,这不是很灵活.
第二个示例表示写入接口的类.它并不关心你使用什么具体对象,只关心它实现了某些行为.这使得该类更加灵活,因为它可以提供任意数量的具体实现来完成其工作.
例如,特定类可能需要执行一些日志记录.如果您编写依赖于TextFileLogger的类,则该类将永远被强制将其日志记录写入文本文件.如果要更改日志记录的行为,则必须更改类本身.该类与其记录器紧密耦合.
但是,如果你编写的类依赖于ILogger接口,然后为类提供TextFileLogger,那么你将完成同样的事情,但是具有更灵活的额外好处.您可以随意提供任何其他类型的ILogger,而无需更改类本身.该类及其记录器现在松散耦合,您的类更灵活.
Tho*_*ing 19
接口是相关方法的集合,仅包含这些方法的签名 - 而不是实际的实现.
如果一个类实现了一个接口(class Car implements IDrivable),它必须为接口中定义的所有签名提供代码.
基本示例:
您必须上课Car and Bike.两者都实现了IDrivable接口:
interface IDrivable
{
void accelerate();
void brake();
}
Run Code Online (Sandbox Code Playgroud)
class Car implements IDrivable
{
void accelerate()
{ System.out.println("Vroom"); }
void brake()
{ System.out.println("Queeeeek");}
}
Run Code Online (Sandbox Code Playgroud)
class Bike implements IDrivable
{
void accelerate()
{ System.out.println("Rattle, Rattle, ..."); }
void brake()
{ System.out.println("..."); }
}
Run Code Online (Sandbox Code Playgroud)
现在让我们假设你有一组对象,它们都是"可驱动的"(它们的类都实现了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());
Run Code Online (Sandbox Code Playgroud)
如果您现在想要遍历该集合,则可以依赖于该集合中的每个对象实现的事实accelerate():
for(IDrivable vehicle: vehicleList)
{
vehicle.accelerate(); //this could be a bike or a car, or anything that implements IDrivable
}
Run Code Online (Sandbox Code Playgroud)
通过调用该接口方法,您不是编程到实现而是编程到接口 - 一个确保调用目标实现某个功能的合同.
使用继承可以实现相同的行为,但是从公共基类派生会导致紧密耦合,这可以使用接口来避免.
现实世界的例子是苹果.其中之一:
对于JDBC,您正在使用该接口java.sql.Connection.但是,每个JDBC驱动程序都提供自己的实现Connection.你不必知道具体的实现什么,因为它符合该Connection接口.
另一个来自java集合框架.有一个java.util.Collection接口,它定义size,add和remove方法(以及许多其他).因此,您可以互换使用所有类型的集合.假设您有以下内容:
public float calculateCoefficient(Collection collection) {
return collection.size() * something / somethingElse;
}
Run Code Online (Sandbox Code Playgroud)
以及另外两种调用此方法的方法.其中一种方法使用a,LinkedList因为它的效率更高,而另一种方法则使用a TreeSet.
因为这两个LinkedList和TreeSet实现Collection接口,可以只使用一种方法来执行系数计算.无需复制代码.
而这里来了"节目的接口" -你不在乎究竟是如何的size()方法来实现,你知道它应该返回集合的大小-即你已经设定的Collection接口,而不是LinkedList和TreeSet特别.
但我的建议是找一本阅读书 - 也许是一本书(例如"Thinking in Java") - 其中详细解释了这个概念.
多态性依赖于对接口的编程,而不是实现.
仅根据抽象类定义的接口操作对象有两个好处:
这极大地减少了子系统之间的实现依赖性,从而导致这种编程原理到接口.
有关此设计的进一步推理,请参见工厂方法模式.
资料来源:GOF的" 设计模式:可重复使用的面向对象软件的元素 "
每个对象都有一个公开的接口。集合有Add、Remove、At等。套接字可能有Send、Receive、Close等。
您实际上可以获得引用的每个对象都有这些接口的具体实现。
这两件事都是显而易见的,但有些不太明显......
您的代码不应依赖于对象的实现细节,而应依赖于其已发布的接口。
如果你采取极端的做法,你只会针对Collection<T>等等(而不是ArrayList<T>)进行编码。更实际的是,只需确保您可以交换概念上相同的内容而不会破坏代码。
举个Collection<T>例子:你有一些东西的集合,你实际上正在使用ArrayList<T>,因为为什么不呢。你应该确保你的代码不会被破坏,比如说,如果你将来最终使用的话LinkedList<T>。