接口和内部类为我们提供了一种将接口与实现分离的更加结构化的方法。
9.1抽象类和抽象方法
如果我们的基类只是希望它被继承从而通过它的接口操作导出类,它本身创建对象没有什么意义,那么我们可以把这个基类设计为抽象类。把在基类中不好实现的方法标记为abstract。这样做可以使类的抽象性更加明确。
9.2接口
interface关键字使得抽象概念更加彻底,只提供了形式,没有任何实现。但它不仅仅是极度抽象的类,它还允许创建出一个可以向上转型成多种类型的类,来实现类似于多重继承的特性。
接口中也可以包含域,但这些域是隐式static final的。
接口中的方法必须是public(可省略不写),实现类中实现方法也必须是public的。
9.3完全解耦
只要一个方法操作的是类而非接口,那么你就只能使用这个类及其子类。如果这个方法还想操作其他类型,就会发生错误。而接口就可大大放宽这种限制,使得我们可以编写复用性高的代码。例如:有一个手机类,接口是播放器play(),有不同的导出类继承这个手机类,一个方法接收手机对象,调用play方法播放音乐。但是这个方法只能接收手机对象和导出类对象。如果我想让电脑播放音乐,由于电脑不属于手机继承体系,所以不能实现这种功能。但是如果我们把播放功能抽象到一个接口里,让手机实现这个接口,电脑实现这个接口,那么这个方法只要接收接口参数即可。实现了解耦合。
如果手机类是我们创建的,我们可以直接添加implements,但是如果它是jar里的或者别人的,我们不能直接修改它怎么办呢?
可以使用适配器模式,创建一个适配器类,实现接口,组合所需要的对象,在方法里调用该对象相应的方法。
9.4Java中的多重继承
一定要记住:使用接口的核心原因就是为了能向上转型成多个基类(以及由此带来的灵活性),第二个原因就是与使用抽象类相同:防止客户端创建该类的对象。
9.5通过继承扩展接口
利用extends关键字可以扩展接口里的方法
9.6适配接口
使用适配器模式来给现有操作接口方法添加新的操作对象是非常有用的。
9.7接口中的域
隐式的static、final的,在enum出现之前(Java SE5)用它当做常量。
9.8嵌套接口
...
9.9接口与工厂
接口是实现多继承的途径,而生成遵循接口对象的典型方式就是工厂方法设计模式。
原始方式:
方法以接口为参数,void action(Service s){...}
调用的时候if(xxx)action(new SImp1());else if(xxx)action(new SImp2());else if....每个调用地方都需要直接提供实现类对象。如果需要修改/增加实现类代码就会很冗余。
工厂方式:
void action(ServiceFactory fac){Service s = fac.getService();....}
只需要在factory里改变即可。
9.10总结
任何抽象性都应该是应真正需求而产生的。应该优先选择类而不是接口。如果接口的必需性变得非常明确,那么就进行重构。接口是重要的工具,但是不要滥用它。