,Java   工具软件   办公软件   操作系统   网络安全   设计在线   程序开发   教程宝典   软件下载   软件论坛,Java
您的位置:软件 > 开发者网络 > 开发工具 > Java > 正文
为什么Java中继承多数是有害的
[文章信息]
作者:
时间:2005-04-28
出处:Java研究组织
责任编辑:方舟
[文章导读]
大多数好的设计者象躲避瘟疫一样来避免使用实现继承
advertisement
热点推荐
· VB实现SQL Server 2000存储过程调用
· Java解析网络数据流的三种特殊方法
· 多媒体教程:网页表单文本域类型
· 体验V5E地形编辑:整体控制
· 打造完美可随意安装的WinXP镜像
[正文]

上一页  1 2  

  脆弱的基类问题

  现在,让我们应用耦合的概念到继承。在一个用extends的继承实现系统中,派生类是非常紧密的和基类耦合,当且这种紧密的连接是不期望的。设计者已经应用了绰号“脆弱的基类问题”去描述这个行为。基础类被认为是脆弱的是,因为你在看起来安全的情况下修改基类,但是当从派生类继承时,新的行为也许引起派生类出现功能紊乱。你不能通过简单的在隔离下检查基类的方法来分辨基类的变化是安全的;而是你也必须看(和测试)所有派生类。而且,你必须检查所有的代码,它们也用在基类和派生类对象中,因为这个代码也许被新的行为所打破。一个对于基础类的简单变化可能导致整个程序不可操作。

  让我们一起检查脆弱的基类和基类耦合的问题。下面的类extends了Java的ArrayList类去使它像一个stack来运转:

class Stack extends ArrayList
{
 private int stack_pointer = 0;

 public void push( Object article )
 {
  add( stack_pointer++, article );
 }

 public Object pop()
 {
  return remove( --stack_pointer );
 }

 public void push_many( Object[] articles )
 {
  for( int i = 0; i < articles.length; ++i )
   push( articles[i] );
 }
}

  甚至一个象这样简单的类也有问题。思考当一个用户平衡继承和用ArrayList的clear()方法去弹出堆栈时:

Stack a_stack = new Stack();
a_stack.push("1");
a_stack.push("2");
a_stack.clear();

  这个代码成功编译,但是因为基类不知道关于stack指针堆栈的情况,这个stack对象当前在一个未定义的状态。下一个对于push()调用把新的项放入索引2的位置。(stack_pointer的当前值),所以stack有效地有三个元素-下边两个是垃圾。(Java的stack类正是有这个问题,不要用它).

  对这个令人讨厌的继承的方法问题的解决办法是为Stack覆盖所有的ArrayList方法,那能够修改数组的状态,所以覆盖正确的操作Stack指针或者抛出一个例外。(removeRange()方法对于抛出一个例外一个好的候选方法)。

  这个方法有两个缺点。第一,如果你覆盖了所有的东西,这个基类应该真正的是一个interface,而不是一个class。如果你不用任何继承方法,在实现继承中就没有这一点。第二,更重要的是,你不能够让一个stack支持所有的ArrayList方法。例如,令人烦恼的removeRange()没有什么作用。唯一实现无用方法的合理的途径是使它抛出一个例外,因为它应该永远不被调用。这个方法有效的把编译错误成为运行错误。不好的方法是,如果方法只是不被定义,编译器会输出一个方法未找到的错误。如果方法存在,但是抛出一个例外,你只有在程序真正的运行时,你才能够发现调用错误。

  对于这个基类问题的一个更好的解决办法是封装数据结构代替用继承。这是新的和改进的Stack的版本:

class Stack
{
 private int stack_pointer = 0;
 private ArrayList the_data = new ArrayList();

 public void push( Object article )
 {
  the_data.add( stack_poniter++, article );
 }

 public Object pop()
 {
  return the_data.remove( --stack_pointer );
 }

 public void push_many( Object[] articles )
 {
  for( int i = 0; i < o.length; ++i )
   push( articles[i] );
 }
}

  到现在为止,一直都不错,但是考虑脆弱的基类问题,我们说你想要在stack创建一个变量, 用它在一段周期内跟踪最大的堆栈尺寸。一个可能的实现也许象下面这样:

class Monitorable_stack extends Stack
{
 private int high_water_mark = 0;
 private int current_size;

 public void push( Object article )
 {
  if( ++current_size > high_water_mark )
   high_water_mark = current_size;
   super.push( article );
 }

 publish Object pop()
 {
  --current_size;
  return super.pop();
 }

 public int maximum_size_so_far()
 {
  return high_water_mark;
 }
}

  这个新类运行的很好,至少是一段时间。不幸的是,这个代码发掘了一个事实,push_many()通过调用push()来运行。首先,这个细节看起来不是一个坏的选择。它简化了代码,并且你能够得到push()的派生类版本,甚至当Monitorable_stack通过Stack的参考来访问的时候,以至于high_water_mark能够正确的更新。

上一页  1 2  

发表评论推荐给朋友我想参加相关培训打印我对此感兴趣订阅电子杂志
天极社区邀请您:写博客日记  上传相片   论坛聊天  订阅电子杂志  推荐网摘   免费图铃工具
笔名:   请您注意:

 遵守国家有关法律、法规,尊重网上道德,承担一切因您的行为而直接或间接引起的法律责任。

 天极网拥有管理笔名和留言的一切权利。
评论:
 
,Java相关内容,Java焦点新闻
  • 把WebLogic EJB程序迁移到JBoss上
  • CORBA对象生命周期之生命周期的评估
  • Java中使用JCOM操作Office对象
  • CORBA对象生命周期之实现和内存管理
  • 轻松实现Java 用户界面编程
  • FVD刺激高清碟机加速商业化 抢占商机最重要
  • 3家搜索引擎集体诉讼8848 吕春维未敢出席
  • 杨元庆:没有准备不会获批的备用方案
  • 军队信息化诞生新领域 电子军务呼之欲出
  • 世界经济论坛公布信息化程度全球最新排名
  • 2004政务绩效评估:政府门户尚处于发展阶段
  • 甲骨文出资5.15亿美元 意图收购RetekInc
  • 技术并购:帮你突破传统增长的“天花板”
  • ,JavaAdvertisement