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 查看一个类的继承关系图 在我们开发过程中: 无论是使用的开发框架自带的类, 还是我们自定义的类都特别多; 并且类之间单继承和多继承频繁使用, 这个继承,不仅仅是一级的继承关系,包括好几 ...
随机推荐
- C#多线程的用法4-线程间的协作lock快捷方式
线程间协作还可通过lock(加锁)方式进行,lock属于C#的Monitor语法糖(Monitor后续讲解).使用简单快捷,如下: /// <summary> /// 多线程协作-lock ...
- sublime text 的小细节设置,让你的代码更优美
这些属性都可以在 首选项>设置-默认 里修改下面也会介绍几个比较常用的几个插件 字体大小: "font_size": 17 高亮编辑中的一行 "highlight_ ...
- Scikit-Learn框架
1. Dataset scikit-learn提供了一些标准数据集(datasets),比如用于分类学习的iris 和 digits 数据集,还有用于归约的boston house prices 数据 ...
- RoutePrefix和Route 路由前缀
使用应用到某个控制器中所有操作的路由前缀来批注该控制器. web api /// <summary> ////// </summary> [RoutePrefix(" ...
- 一句话搞定-phpStudy安装yaf扩展
首先下载phpStudyX64位的,然后傻瓜式安装,安装完下载yaf,由于yaf扩展的网站在国外很难下载,需要FQ,所以我这里下载了yaf5.6nts.zip,解压后把php_yaf.dll这个文件粘 ...
- elasticsearch报错expected <block end>, but found BlockMappingStart解决方法
我用的是elasticsearch2.4.0,在修改完配置文件就出现类似格式 expected <block end>, but found BlockMappingStart...... ...
- Jmeter之解决烦人的中文乱码问题
Jmeter是一款国外开源工具,所以就跟LR一样,对中文的支持不是很好,经常会有同学录制脚本后回放或者是发送HTTP请求,看到响应报文里面有乱码! 那如何才能解决这个问题呢?我们分2个情况来分析: 一 ...
- 最大流dinic模板
循环版,点的编号从0开始: ; ; const int INF = 0x3f3f3f3f; struct Edge { int to, next, cap, flow; }edge[MAXM]; in ...
- httpclient 学习
Http协议的重要性相信不用我多说了,HttpClient相比传统JDK自带的URLConnection,增加了易用性和灵活性,它不仅是客户端发送Http请求变得容易,而且也方便了开发人员测试接口(基 ...
- php 自己封装的一些函数
手机归属地函数 function get_mobile_area($phone){ $sms = array('province'=>'', 'supplier'=>''); //初始化变 ...