Java:设计类的继承关系时的技巧
继承设计的技巧:
(1)将公共操作和域放置在超类
(2)不要使用受保护的域
有些程序员认为,将大多数的实例域定义为protected是一个不错的主意,只有这样,子类才能够在需要的时候直接访问他们。然而,protected 机制并不能够带来更好的保护,其原因主要有两点。第一,子类集合是无限制的,任何一个人都能够由某个类派生一个子类,并编写代码以直接访问 protected的实例域,从而破坏了封装性。第二,在Java程序设计语言中,在同一个包中的所有类都可以访问protected域,而不管它是否为 这个类的子类。
(3)使用继承实现“is-a”关系
使用继承很容易得到节省代码的目的,但有时候也被人们滥用了。例如,假设需要定义一个钟点工(Contractor)类。钟点工的信息包含姓名和雇佣日 期,但是没有薪水。他们按小时计薪,并且不会因为拖延时间而获得加薪。这似乎在诱导人们由Employee派生出子类Constractor,然后再增加 一个hourlyWage域。
|
class Contractor extends Employee { …. private double hourlyWage; } |
这并不是一个好主意。因为这样一来,每个钟点工对象中都包含了薪水和计时工资这两个域。在实现打印支票或税单方法的时候,会到来无尽的麻烦,并且会多些很多代码。
钟点工与雇员之间不属于“is-a”关系。钟点工不是特殊的雇员。
(4)除非所有继承的方法都有意义,否则不要使用继承。
假设想编写一个Holiday类。毫无疑问,每个假日也是一日,并且一日可以用GregorianCalendar类的实例表示,因此可以使用继承。
|
class Holiday extends GregorianCalendar { …………. } |
很遗憾,在继承的操作中,假日集不是封闭的。在GregorianCalendar中有一个共有方法add,可以将假日转换成非假日:
|
Holiday Christmas; christmas.add(Calendar.DAY_OF_MONTH,12); |
因此,继承对于这个例子来时并不太适宜。
(5)在覆盖方法的时候,不要改变预期的行为。
置换原则不仅应用于语法,而且也可以应用于行为,这似乎更加重要。在覆盖一个方法的时候,不应该毫无缘由的改变行为的内涵。就这一点而言,编译器不会提供 任何帮助,即编译器不会检查重定义的方法是否有意义。例如,可以重定义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属于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:设计类的继承关系时的技巧的更多相关文章
- Java异常类的继承关系图
- (转)Java:类与继承
原文地址: http://www.cnblogs.com/dolphin0520/p/3803432.html 对于面向对象的程序设计语言来说,类毫无疑问是其最重要的基础.抽象.封装.继承.多态这四大 ...
- Java:类与继承
Java:类与继承 对于面向对象的程序设计语言来说,类毫无疑问是其最重要的基础.抽象.封装.继承.多态这四大特性都离不开类,只有存在类,才能体现面向对象编程的特点,今天我们就来了解一些类与继承的相关知 ...
- 【47】java的类之间的关系:泛化、依赖、关联、实现、聚合、组合
java的类之间的关系:泛化.依赖.关联.实现.聚合.组合 泛化: • 泛化关系(Generalization)也就是继承关系,也称为"is-a-kind-of"关系,泛化关系用于 ...
- Java:类与继承(隐藏和覆盖的问题)
盒子先生金金 Java:类与继承(隐藏和覆盖的问题) Java:类与继承 Java:类与继承 对于面向对象的程序设计语言来说,类毫无疑问是其最重要的基础.抽象.封装.继承.多态这四大特性都离不 ...
- phpstorm查看类的继承关系
在看一些框架源码时,有些类有很多的继承或者接口,有一款神奇的帮助很重要 选中一个类文件,右键,选择diagrams->show diagrams 即可得到类的继承关系,如上右图 使用函数 fun ...
- 游戏编程之Unity常用脚本类的继承关系
前言学习Unity开发引擎的初学者会接触大量的脚本类,而这些类之间的关系往往容易被忽略.本文对Unity引擎开发中的一些常用类及其关系进行了简单的归纳总结. 博文首发地址:http://tieba.b ...
- [Android Studio] Android Studio中查看类的继承关系
转载自:http://blog.csdn.net/hyr83960944/article/details/38098091 查看类的继承关系的快捷键F4,在Android Studio常用快捷键这篇文 ...
- Pycharm 查看一个类的继承关系图
Pycharm 查看一个类的继承关系图 在我们开发过程中: 无论是使用的开发框架自带的类, 还是我们自定义的类都特别多; 并且类之间单继承和多继承频繁使用, 这个继承,不仅仅是一级的继承关系,包括好几 ...
随机推荐
- MYSQL报错注入方法整理
1.通过floor暴错 /*数据库版本*/ SQL http://www.hackblog.cn/sql.php?id=1 and(select 1 from(select count(*),conc ...
- 第一天的php体验
第一次了解php.以前对于程序猿的认知是很片面的.因为没有了解过.今天通过一天的了解交流,有了新的认知.对于这个主要应用于前端的语言还是很有兴趣的.毕竟可以亲眼看到自己做出来的网页,心里的成就感肯定满 ...
- 如何在.xml中配置Servlet信息
在编写好servlet文件后需要在web.xml文件下配置servlet,才能使servlet在服务器上运行.基本配置方式如下所示 <context-param> <param-na ...
- APP应用测试技巧
分页数据 测试分页数据,必须要满足一页数据,根据APP设置的分页数据准备一些测试数据. 满足一页数据的时候上下滑动瀑布流时, 页面数据是否会正常展示: 是否会出现第二页请求不到数据: 是否会出现重复加 ...
- linux基础简答(1)
linux基础简答题 扇区及其4个主分区的原因 在第一个扇区中,保存着引导记录和分区信息,容量为512bytes,主引导记录(相当于MBR)446 bytes,分区表64bytes,记录每个分区信息要 ...
- 《NoSQL精粹》读书笔记
NoSQL数据库数据模型的一般分类: 1. 键值数据模型 2. 文档数据模型 3. 列族数据模型 4. 图数据模型 常见NoSQL数据库: Redis, Cassandra, MongoDB, Neo ...
- 运维之Linux基础知识(三)
运维之Linux基础知识(三) 1. 查看文本 cat tac more less head tail 1.1 cat 连接并显示文件 cat -n:在显示的时候,将每一行编号 -E:显示结束符$ - ...
- 【Ubuntu 16】深入Ubuntu文件系统
Ubuntu文件系统的设计目的就是把文件有序地组织在一起,提供一个从逻辑上组织文件的文件系统.除了文件的组织外,文件安全也是文件系统的设计要点,所以文件的访问权限是文件系统不可缺少的组成部分 Ubun ...
- C#异步编程(async and await)及异步方法同步调用
1.什么是异步? 异步操作通常用于执行完成时间可能较长的任务,如打开大文件.连接远程计算机或查询数据库=异步操作在主应用程序线程以外的线程中执行.应用程序调用方法异步执行某个操作时,应用程序可在异步方 ...
- Scala中柯里化函数
高阶函数转一阶函数: val add1 = (x: Int) => x + 5 def add2(x: Int)(y: Int) = x + y //传入一个参数转换为一阶函数 def add3 ...