答案 1
简单地说,而不是以这样一种方式编写你的类:
我依靠这个特定的班级来完成我的工作
你写它的方式是
我依靠任何做这些事情的班级来完成我的工作。
第一个示例表示一个类,该类依赖于特定的具体实现来完成其工作。从本质上讲,这并不是很灵活。
第二个示例表示写入接口的类。它不在乎你使用什么具体对象,它只是关心它实现了某些行为。这使得该类更加灵活,因为它可以提供任意数量的具体实现来完成其工作。
例如,特定类可能需要执行一些日志记录。如果将类编写为依赖于 TextFileLogger,则该类将永远被迫将其日志记录写出到文本文件中。如果要更改日志记录的行为,则必须更改类本身。该类与其记录器紧密耦合。
但是,如果您编写该类以依赖于 ILogger 接口,然后为该类提供 TextFileLogger,则您将完成相同的任务,但具有更加灵活的额外好处。您可以随意提供任何其他类型的ILogger,而无需更改类本身。该类及其记录器现在是松散耦合的,并且您的类更加灵活。
答案 2
接口是相关方法的集合,仅包含这些方法的签名,不包含实际实现。
如果一个类实现了一个接口 (),它必须为接口中定义的所有签名提供代码。class Car implements IDrivable
基本示例:
您必须对汽车和自行车进行分类。两者都实现了接口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("..."); }
}
现在,让我们假设您有一个对象集合,这些对象都是“可驾驶的”(它们的类都实现了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());
如果您现在想要遍历该集合,则可以依赖于这样一个事实,即该集合中的每个对象都实现了:accelerate()
for(IDrivable vehicle: vehicleList)
{
vehicle.accelerate(); //this could be a bike or a car, or anything that implements IDrivable
}
通过调用该接口方法,您不是对实现进行编程,而是对接口进行编程 - 确保调用目标实现特定功能的协定。
使用继承可以实现相同的行为,但是从公共基类派生会导致紧密耦合,而使用接口可以避免这种情况。
推荐
标签