-
将公共操作和字段放在超类
这就是为什么将姓名字段放在 Person 类中,而没有将它放在 Employee 和 Student类中的原因。
-
不要使用受保护的字段
有些程序员认为,将大多数的实例字段定义为 protected 是一个不错的主意,“以防万一”,这样子类能够在需要的时候直接访问这些字段。然而,protected 机制并不能够带来更多的保护,这有两方面的原因:
1. 子类集合是无限制的,任何一个人都能够由你的类派生一个子类,然后编写代码以直接访问 protected 实例字段,从而破坏了封装性。
1. 在 Java 中,在同一个包中的所有类都可以访问 proteced 字段,而不管它们是否为这个类的子类。不过,protected 方法对于指示那些不提供一般用途而应在子类中重新定义的方法很有用。
-
使用继承实现 “is-a” 关系
使用继承很容易达到节省代码的目的,但有时候也被人们滥用。例如,假设需要定义一个钟点工(Contractor)类。钟点工有姓名和雇佣日期,但是没有工资。他们按小时计薪,并且不会因为拖延时间而获得加薪。这似乎在诱导人们由 Employee 派生出子类 Contractor,然后再增加一个 hourlyWage 字段。
public class Contractor extends Employee {
private double hourlyWage;
...
}
不过,这并不是一个好主意。因为这样一来,每个钟点对象中都包含了工资和时薪这两个字段。在实现打印时薪或税单的方法时,这会带来无尽的麻烦,与不采用继承相比,使用继承实现最后反而会写多写很多代码。
钟点工与员工之间不属于“ is-a” 关系。钟点工不是特殊的员工。
-
除非所有继承的方法都有意义,否则不要使用继承
假设想编写一个 Holiday 类。毫无疑问,每个假日也是一日,并且一天可以用 GregorianCalendar 类的实例表示,因此可以使用继承。
class Holiday extends CregorianCalendar { . . .}
很遗憾,在继承的操作中,假日集合不是封闭的。在 GregorianCalendar 中有一个公有方法 add,可以将假日转换成非假日:
Holiday Christmas;
Christmas.add(Calendar.DAY_OF_MONTH, 12);
因此,继承对于这个例子来说并不太适宜。
需要指出,如果扩展 LocalDate 就不会出现这个问题。由于这个 LocalDate 类是不可变的,所以没有任何方法能够把假日变成非假日。 -
在覆盖方法时,不要改变预期的行为
替换原则不仅应用于语法,更重要的是,它也适用于行为。在覆盖一个方法的时候,不应该毫无原由地改变它的行为。就这一点而言,编译器不会提供任何帮助,即编译器不会检查重新定义的方法是否有意义。例如,可以重新定义 Holiday 类中的 add 方法来“修正”这个方法的问题,可能什么也不做,或者抛出一个异常,或者是前进到下一个假日。
然而,这样一个“修正”违反了替换原则。对于以下语句序列
int d1 = x.get(Calendar.DAY_OF_MONTH);
x.add(Calendar.DAY_OF_MONTH, 1);
int d2 = x.get(Calendar.DAY_OF_MONTH);
System.out.println(d2 - d1);
不管 x 的类型是 CregorianCalendar 还是 Holiday,执行上述语句后都应该得到预期行为。当然,这个难题。理智和不理智的人们可能就预期行为是什么争论不休。。例如,有些人争论说,置换原则要求 Manager.equals 忽略 bonus 字段,因为 Employee.equals 就忽略了这个字段。实际上,凭空讨论这些问题毫无意义。归根结底,关键在于在子类中覆盖方法时,不要偏离最初的设计想法。
-
使用多态,而不要使用类型信息
只要看到类似下面的代码
if(x is of type 1) {
action1(x);
}else if(x is of type 2) {
action2(x);
}
都应该考虑使用多态性。
action1 与 action2 表示的是相同的概念吗?如果是相同的概念,就应该为这个概念定义一个方法,并将其放置在两个类型的超类或接口中,然后,就可以调用
x.action();
使用多态性固有的动态分派机制执行正确的动作。使用多态方法或接口实现的代码比使用多个类型检测的代码更易于维护和扩展。
-
不要滥用反射
反射机制使人们可以在运行时查看字段和方法,从而编写出更具有通用性的程序。这种功能对于编写系统程序及其重要,但是通常不适用于编写应用程序。反射是很脆弱的,如果使用反射,编译器将无法帮助你查找编程错误,因此只有在运行时才会发现错误并导致异常。
继承的设计技巧(学习 Java 编程语言 055)
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
推荐阅读更多精彩内容
- 1. 多态 一个对象变量可以指示多种实际类型的现象被称为多态(polymorphism)。多态是同一个行为具有多个...
- 如果将一个类声明为 abstract,那么这个类就是抽象类。抽象类可以包含抽象方法、字段和具体方法。抽象类不能被实...
- 将一个类型强制转换成另外一个类型的过程被称为强制类型转换。Java 程序设计语言提供了一种专门用于进行强制类型转换...