Chap5 专题:Java语言的接口
5.1 What?
是一些方法特征的集合,这些方法特征来自于具体方法,但他们一般都是来自于一些在系统中不断出现的方法。一个接口只有方法的特征,而没有实现,所以这些方法在不同的地方被实现时,可以具有完全不同的行为。
5.2 Why?
没有接口会怎样
没有接口,可插入性就没有保证
接口是对可插入性的保证
接口使可插入性变得可能
在一个类等级结构中的任何一类都可以实现一个接口,这个接口会影响到此类的所有子类,但是不会影响到此类的任何超类。此类将不得不实现这个接口所规定的方法,而其子类则可以从此类自动继承到这些方法,当然也可以选择之换掉所有的这些方法,或者其中的某一些方法。
这售后,这些子类就具有了可插入性。
关联的可插入性
一个对象需要完成一项任务,所以需要知道其他的对象,并且调用其他对象的方法。这个对象对其他对象的知识叫做关联(Association)。
如果一个关联不是针对一个具体类的,而是针对一个接口的,那么任何实现这个接口的类就都可以满足要求。换言之,当前对象并不在意所关联的是哪一个具体类,而这样做的唯一条件是他们都实现某个接口。
调用的可插入性
一个对象不可避免的需要调用其他对象的方法。这种调用不一定非得是某一个具体类,而可以是一个接口。这样以来,任何实现了这个接口的具体类都可以被当前对象调用;而当前对象调用的是哪个具体类的实例则完全可以动态的决定。
接口使得软件系统在灵活性和可扩展性、可插入性方面得到保证。
类型
Java接口(以及Java抽象类)用来声明一个新的类型。
在理想的情况下,一个具体Java类应当只实现Java接口和抽象类中声明过的方法,而不应当给出多余的方法。
类型的等级结构
Java接口(抽象类)一般用来作为一个类型的等级结构的起点。
混合类型(Mixin Type)
如果一个类已经有一个主要的超类型,那么通过实现一个接口,这个类可以拥有另一个次要的超类型。
5.3 Java接口常见的用法
单方法接口
可以看作是C语言中函数指针的对应物。
标识接口
是没有任何方法和属性的接口。
常量接口
Chap6 专题:抽象类
6.1 What?
抽象类仅提供一个类型的部分实现。可以有实例变量,以及一个或者多个构造函数。可以同事有抽象方法和具体方法。但是它不会有实例,只能够被继承。
抽象类和子类的关系实际上是模版方法模式的应用。
6.2 用途
通常代表一个抽象概念,他提供一个继承的出发点。
一个设计师设计一个新的抽象类,一定是用来继承的,而这一个声明倒过来也是对的:具体类不是用来继承的。
具体类不是用来继承的
Scott Meyers曾指出,只要有可能,不要从具体类继承。
上图的设计是所有的Java设计师都应当努力做到的。
代码重构的建议
A:具体类 B:具体类,重构方法是建立一个抽象类或者接口C,然后让A和B成为C的子类
这就是LSP(里氏代换原则)。
抽象类应当拥有尽可能多的共同代码
在一个从抽象类到多个具体类的继承关系中,共同的代码应当尽量移动到抽象类里。(共同的代码应该往上移动)可以提高代码的复用率。
一个典型的例子就是策略模式。在策略模式中,抽象策略角色的分量越重越好,也就是说尽可能将公共的方法移动到抽象策略角色中。
抽象类应当拥有尽可能少的数据
一个对象的数据不论是否使用都会占用资源。
6.3 基于抽象类的模式和原则
针对抽象编程
针对抽象编程,不要针对具体编程。这就是DIP所讲的内容。
正确使用继承
接口继承
实现继承
抽象类是用来继承的,因此抽象类注定要与继承关联在一起。只要可能,尽量使用合成(Composition),而不要使用继承来达到复用的目的。(见CARP)
模板方法模式
不仅仅使用抽象类和继承关系作为对模式所涉及的角色的抽象化,他根本就是关于继承的模式。(后面会讲到)
6.4 什么时候才应当使用继承复用
当以下的Coad条件全部被满足时,才应当使用继承关系:
(1) 子类是超类的一个特殊种类,而不是超类的一个角色,也就是要区分“Has-A”与“Is-A”两种关系的不同。Has-A关系应当使用聚合关系描述,而只有Is-A关系才符合继承关系。
(2) 永远不会出现需要将子类换成另一个类的子类的情况。
(3) 子类具有扩展超类的责任,而不是具有置换掉(Override)或注销掉(Nullify)超类的责任。
(4) 只有从分类学角度上有意义时,才可以使用继承,不要从工具类继承。
LSP是可否使用继承关系的准绳。上面的Coad条件不如LSP严格。一般情况下,凡是不符合Coad条件的均不会满足LSP。
区分“Has-A”与“Is-A”
子类扩展超类的责任
不要从工具类继承