为什么Java中继承多数是有害的

2016-01-29 12:49 7 1 收藏

为什么Java中继承多数是有害的,为什么Java中继承多数是有害的

【 tulaoshi.com - Java 】

  大多数好的设计者象躲避瘟疫一样来避免使用实现继承(extends 关系)。实际上80%的代码应该完全用interfaces写,而不是通过extends。“Java设计模式”一书详细阐述了怎样用接口继承代替实现继承。这篇文章描述设计者为什么会这么作。

  Extends是有害的;也许对于Charles Manson这个级别的不是,但是足够糟糕的它应该在任何可能的时候被避开。“JAVA设计模式”一书花了很大的部分讨论用interface继承代替实现继承。

  好的设计者在他的代码中,大部分用interface,而不是具体的基类。本文讨论为什么设计者会这样选择,并且也介绍一些基于interface的编程基础。

  接口(Interface)和类(Class)?

  一次,我参加一个Java用户组的会议。在会议中,Jams Gosling(Java之父)做发起人讲话。在那令人难忘的Q&A部分中,有人问他:“如果你重新构造Java,你想改变什么?”。“我想抛弃classes”他回答。在笑声平息后,它解释说,真正的问题不是由于class本身,而是实现继承(extends) 关系。接口继承(implements关系)是更好的。你应该尽可能的避免实现继承。

  失去了灵活性

  为什么你应该避免实现继承呢?第一个问题是明确的使用具体类名将你固定到特定的实现,给底层的改变增加了不必要的困难。

  在当前的敏捷编程方法中,核心是并行的设计和开发的概念。在你详细设计程序前,你开始编程。这个技术不同于传统方法的形式----传统的方式是设计应该在编码开始前完成----但是许多成功的项目已经证明你能够更快速的开发高质量代码,相对于传统的按部就班的方法。但是在并行开发的核心是主张灵活性。你不得不以某一种方式写你的代码以至于最新发现的需求能够尽可能没有痛苦的合并到已有的代码中。

  胜于实现你也许需要的特征,你只需实现你明确需要的特征,而且适度的对变化的包容。如果你没有这种灵活,并行的开发,那简直不可能。

  对于Inteface的编程是灵活结构的核心。为了说明为什么,让我们看一下当使用它们的时候,会发生什么。考虑下面的代码:

  f()
  {
  LinkedList list = new LinkedList();
  //...
  g( list );
  }

  g( LinkedList list )
  {
  list.add( ... );
  g2( list )
  }

  假设一个对于快速查询的需求被提出,以至于这个LinkedList不能够解决。你需要用HashSet来代替它。在已有代码中,变化不能够局部化,因为你不仅仅需要修改f()也需要修改g()(它带有LinkedList参数),并且还有g()把列表传递给的任何代码。象下面这样重写代码:

  f()
  {
  Collection list = new LinkedList();
  //...
  g( list );
  }

  g( Collection list )
  {
  list.add( ... );
  g2( list )
  }

  这样修改Linked list成hash,可能只是简单的用new HashSet()代替new LinkedList()。就这样。没有其他的需要修改的地方。

  作为另一个例子,比较下面两段代码:

  f()
  {
  Collection c = new HashSet();
  //...
  g( c );
  }

  g( Collection c )
  {
  for( Iterator i = c.iterator(); i.hasNext() )
  do_something_with( i.next() );
  }

  和

  f2()
  {
  Collection c = new HashSet();
  //...
  g2( c.iterator() );
  }

  g2( Iterator i )
  {
  while( i.hasNext() )
  do_something_with( i.next() );
  }


  g2()方法现在能够遍历Collection的派生,就像你能够从Map中得到的键值对。事实上,你能够写iterator,它产生数据,代替遍历一个Collection。你能够写iterator,它从测试的框架或者文件中得到信息。这会有巨大的灵活性。

  耦合

  对于实现继承,一个更加关键的问题是耦合---令人烦躁的依赖,就是那种程序的一部分对于另一部分的依赖。全局变量提供经典的例子,证明为什么强耦合会引起麻烦。例如,如果你改变全局变量的类型,那么所有用到这个变量的函数也许都被影响,所以所有这些代码都要被检查,变更和重新测试。而且,所有用到这个变量的函数通过这个变量相互耦合。也就是,如果一个变量值在难以使用的时候被改变,一个函数也许就不正确的影响了另一个函数的行为。这个问题显著的隐藏于多线程的程序。

  作为一个设计者,你应该努力最小化耦合关系。你不能一并消除耦合,因为从一个类的对象到另一个类的对象的方法调用是一个松耦合的形式。你不可能有一个程序,它没有任何的耦合。然而,你能够通过遵守OO规则,最小化一定的耦合(最重要的是,一

来源:https://www.tulaoshi.com/n/20160129/1487685.html

延伸阅读
标签: Java JAVA基础
计算机学院研二的兄弟与我讨论Java,一见面,几个问题全是关于接口,接口有什么用?为什么要用接口?什么时候该使用接口?很庆幸他们不是问我Java如何连接SQL Server,或者是如何开发J2EE应用,这类问题有杀伤力,避之则吉。今年计算机学院本科有个毕业设计课题是做J2ME,选这个题目的学生在5月末都还在苦着脸研究java.util.*这...
什么是遗嘱继承  关于遗嘱法律知识有很多,什么是遗嘱继承,遗嘱继承的情形有哪些?有人去世前会把自己一些财产想要继承给自己想要继承的人,对于遗嘱继承人也有一些相关的顺序,第一继承人是配偶、子女、父母。第二顺序是兄弟、姐妹、祖父母。对于相关遗嘱继承的相关法律知识图老师为大家分享了内容如,快来了解一下吧! 遗嘱继承是指...
/**  * pTitle: 继承Thread,实现线程/p  * pDescription: 通过继承Thread类,实现其run方法,实现自己的线程/p  * pCopyright: Copyright (c) 2003/p  * pFilename: oneThread.java/p  * @version 1.0  */ public class oneThread extends Thread { /**  *br方法说明:构造器,本类没有使用  *br输入...
class tree { /**  *br方法说明:树的树根  *br输入参数:  *br返回类型:  */ public void root() { String sSite = "土壤中"; String sFunction = "吸收养份"; print("位置:"+sSite); print("功能:"+sFunction); } /**  *br方法说明:树的树...
为什么大多数女明星都生女儿 英国科学家发现,常吃素食的 孕妇 比较容易生女儿,英国的男婴与女婴数量比例为106:100,但是吃素的孕妇生下儿子与女儿的比例为85:100。常吃素会改变女性引导分泌物的酸碱度,加上素食中包含模拟雌性荷尔蒙(如雌性激素)活动的一些化学物质所以常吃素食不利于携带雄性基因的精子存活...

经验教程

693

收藏

94
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部