Java学习day036 继承的设计技巧

使用的教材是java核心技术卷1,我将跟着这本书的章节同时配合视频资源来进行学习基础java知识。

day036   继承的设计技巧


在学习继承的最后,给出一些对设计继承关系很有帮助的建议。

1.将公共操作和域放在超类

这就是为什么将姓名域放在Person类中,而没有将它放在Employee和Student类中的原因。

2.不要使用受保护的域

有些程序员认为,将大多数的实例域定义为protected是一个不错的主意,只有这样,子类才能够在需要的时候直接访问它们。然而,protected机制并不能够带来更好的保护,其原因主要有两点。第一,子类集合是无限制的,任何一个人都能够由某个类派生一个子类,并编写代码以直接访问protected的实例域,从而破坏了封装性。第二,在Java程序设计语言中,在同一个包中的所有类都可以访问proteced域,而不管它是否为这个类的子类。

不过,protected方法对于指示那些不提供一般用途而应在子类中重新定义的方法很有用。

3.使用继承实现“is-a”关系

使用继承很容易达到节省代码的目的,但有时候也被人们滥用了。例如,假设需要定义一个钟点工类。钟点工的信息包含姓名和雇佣日期,但是没有薪水。他们按小时计薪,并且不会因为拖延时间而获得加薪-这似乎在诱导人们由Employee派生出子类Contractor,然后再增加一个hourlyWage域。

publi class Contractor extends Employee
{
    private double hourlyWage;
    ...
}

这并不是一个好主意。因为这样一来,每个钟点工对象中都包含了薪水和计时工资这两个域。在实现打印支票或税单方法的时候,会带来诞的麻烦,并且与不采用继承,会多写很多代码。

钟点工与雇员之间不属于“is-a”关系。钟点工不是特殊的雇员。

4.除非所有继承的方法都有意义,否则不要使用继承

假设想编写一个Holiday类3毫无疑问,每个假日也是一日,并且一日可以用GregorianCalendar类的实例表示,因此可以使用继承。

class Holiday extends CregorianCalendar{...}

很遗憾,在继承的操作中,假日集不是封闭的。在GregorianCalendar中有一个公有方法add,可以将假日转换成非假日:

Holiday Christmas;
Christmas.add(Calendar.DAY_OF_MONTH,12);

因此,继承对于这个例子来说并不太适宜。

需要指出,如果扩展LocalDate就不会出现这个问题。由于这个类是不可变的,所以没有任何方法会把假日变成非假日。

5.在覆盖方法时,不要改变预期的行为

置换原则不仅应用于语法,而且也可以应用于行为,这似乎更加重要。在覆盖一个方法的时候,不应该毫无原由地改变行为的内涵。就这一点而言,编译器不会提供任何帮助,即编译器不会检查重新定义的方法是否有意义。例如,可以重定义Holiday类中add方法“修正”原方法的问题,或什么也不做,或抛出一个异常,或继续到下一个假日。

然而这些都违反了置换原则。语句序列

int dl=x.get(Calendar.DAY_OF_MONTH)
;x.add(Calendar.DAY_OF_MONTH,1);
int d2=x.get(Calendar.DAY_OF_HONTH);
System.out.println(d2-dl);

不管x属于GregorianCalendar类,还是属于Holiday类,执行上述语句后都应该得到预期的行为。

当然,这样可能会引起某些争议。人们可能就预期行为的含义争论不休。例如,有些人争论说,置换原则要求Manager.equals不处理bonus域,因为Employee.equals没有它。实际上,凭空讨论这些问题毫无意义。关键在于,在覆盖子类中的方法时,不要偏离最初的设计想法。

6.使用多态,而非类型信息

无论什么时候,对于下面这种形式的代码

if(x is of type1)
    action1(x);
else if(x is of type2)
    action2(x);

都应该考虑使用多态性。

action1与action2表示的是相同的概念吗?如果是相同的概念,就应该为这个概念定义一个方法,并将其放置在两个类的超类或接口中,然后,就可以调用

X.action();

以便使用多态性提供的动态分派机制执行相应的动作。

使用多态方法或接口编写的代码比使用对多种类型进行检测的代码更加易于维护和扩展。

7.不要过多地使用反射

反射机制使得人们可以通过在运行时查看域和方法,让人们编写出更具有通用性的程序。这种功能对于编写系统程序来说极其实用,但是通常不适于编写应用程序。反射是很脆弱的,即编译器很难帮助人们发现程序中的错误,因此只有在运行时才发现错误并导致异常。


前面的学习了解了Java支持面向对象编程的基础内容:类、继承和多态。打算再重复看一遍,顺便看视频巩固一下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值