`
jokermanager
  • 浏览: 140960 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

为什么说Java中继承是有害的(2)

阅读更多

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

 

 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规则,最小化一定的耦合(最重要的是,一个对象的实现应该完全隐藏于使用他 的对象)。例如,一个对象的实例变量(不是常量的成员域),应该总是private。我意思是某段时期的,无例外的,不断的。(你能够偶尔有效地使用 protected方法,但是protected实例变量是可憎的事)同样的原因你应该不用get/set函数---他们对于是一个域公用只是使人感到过 于复杂的方式(尽管返回修饰的对象而不是基本类型值的访问函数是在某些情况下是由原因的,那种情况下,返回的对象类是一个在设计时的关键抽象)。
   这里,我不是书生气。在我自己的工作中,我发现一个直接的相互关系在我OO方法的严格之间,快速代码开发和容易的代码实现。无论什么时候我违反中心的 OO原则,如实现隐藏,我结果重写那个代码(一般因为代码是不可调试的)。我没有时间重写代码,所以我遵循那些规则。我关心的完全实用?我对干净的原因没 有兴趣。
脆弱的基类问题
  现在,让我们应用耦合的概念到继承。在一个用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();

 

分享到:
评论

相关推荐

    为什么说Java中继承是有害的

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

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

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

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

    全局变量提供经典的例子,证明为什么强耦合会引起麻烦。例如,如果你改变全局变量的类型,那么所有用到这个变量的函数也许都被影响,所以所有这些代码都要被检查,变更和重新测试。而且,所有用到这个变量的函数通过...

    Thinking in Java简体中文(全)

    7.6.9 为什么要用内部类:控制框架 7.7 构建器和多形性 7.7.1 构建器的调用顺序 7.7.2 继承和finalize() 7.7.3 构建器内部的多形性方法的行为 7.8 通过继承进行设计 7.8.1 纯继承与扩展 7.8.2 下溯造型与运行期类型...

    java联想(中文)

    7.6.9 为什么要用内部类:控制框架 7.7 构建器和多形性 7.7.1 构建器的调用顺序 7.7.2 继承和finalize() 7.7.3 构建器内部的多形性方法的行为 7.8 通过继承进行设计 7.8.1 纯继承与扩展 7.8.2 下溯造型与运行期类型...

    Thinking in Java 中文第四版+习题答案

    7.6.9 为什么要用内部类:控制框架 7.7 构建器和多形性 7.7.1 构建器的调用顺序 7.7.2 继承和 7.7.3 构建器内部的多形性方法的行为 7.8 通过继承进行设计 7.8.1 纯继承与扩展 7.8.2 下溯造型与运行期类型标识 7.9 ...

    java 编程入门思考

    7.6.9 为什么要用内部类:控制框架 7.7 构建器和多形性 7.7.1 构建器的调用顺序 7.7.2 继承和finalize() 7.7.3 构建器内部的多形性方法的行为 7.8 通过继承进行设计 7.8.1 纯继承与扩展 7.8.2 下溯造型与运行期类型...

    Java初学者入门教学

    7.6.9 为什么要用内部类:控制框架 7.7 构建器和多形性 7.7.1 构建器的调用顺序 7.7.2 继承和finalize() 7.7.3 构建器内部的多形性方法的行为 7.8 通过继承进行设计 7.8.1 纯继承与扩展 7.8.2 下溯造型与运行期类型...

    JAVA_Thinking in Java

    7.6.9 为什么要用内部类:控制框架 7.7 构建器和多形性 7.7.1 构建器的调用顺序 7.7.2 继承和finalize() 7.7.3 构建器内部的多形性方法的行为 7.8 通过继承进行设计 7.8.1 纯继承与扩展 7.8.2 下溯造型与运行期类型...

    毕业设计 健身房管理系统 java后端.zip

    Java能够自动处理对象的引用和间接引用,实现自动的无用单元收集,使用户不必为存储管理问题烦恼,能更多的时间和精力花在研发上。 面向对象 Java是一个面向对象的语言。对程序员来说,这意味着要注意其中的数据和...

    基于java的校园二手交易系统毕业设计.zip

    Java能够自动处理对象的引用和间接引用,实现自动的无用单元收集,使用户不必为存储管理问题烦恼,能更多的时间和精力花在研发上。 面向对象 Java是一个面向对象的语言。对程序员来说,这意味着要注意其中的数据和...

    毕业设计管理系统java服务端,采用spring mvc.zip

    Java能够自动处理对象的引用和间接引用,实现自动的无用单元收集,使用户不必为存储管理问题烦恼,能更多的时间和精力花在研发上。 面向对象 Java是一个面向对象的语言。对程序员来说,这意味着要注意其中的数据和...

    基于java web技术的毕业设计商城项目。.zip

    Java能够自动处理对象的引用和间接引用,实现自动的无用单元收集,使用户不必为存储管理问题烦恼,能更多的时间和精力花在研发上。 面向对象 Java是一个面向对象的语言。对程序员来说,这意味着要注意其中的数据和...

    毕业设计,关于新浪微博API的Java编程..zip

    Java能够自动处理对象的引用和间接引用,实现自动的无用单元收集,使用户不必为存储管理问题烦恼,能更多的时间和精力花在研发上。 面向对象 Java是一个面向对象的语言。对程序员来说,这意味着要注意其中的数据和...

    毕业设计基于Cesium时空数据可视化后台Java SSM框架.zip

    Java能够自动处理对象的引用和间接引用,实现自动的无用单元收集,使用户不必为存储管理问题烦恼,能更多的时间和精力花在研发上。 面向对象 Java是一个面向对象的语言。对程序员来说,这意味着要注意其中的数据和...

    本科毕业设计项目-Java电影推荐系统-管理后台.zip

    Java能够自动处理对象的引用和间接引用,实现自动的无用单元收集,使用户不必为存储管理问题烦恼,能更多的时间和精力花在研发上。 面向对象 Java是一个面向对象的语言。对程序员来说,这意味着要注意其中的数据和...

    使用Spring Boot的小型诊所信息系统,毕业设计Java版.zip

    Java能够自动处理对象的引用和间接引用,实现自动的无用单元收集,使用户不必为存储管理问题烦恼,能更多的时间和精力花在研发上。 面向对象 Java是一个面向对象的语言。对程序员来说,这意味着要注意其中的数据和...

    毕业设计---蚁群算法实现vrp问题java版本.zip

    Java能够自动处理对象的引用和间接引用,实现自动的无用单元收集,使用户不必为存储管理问题烦恼,能更多的时间和精力花在研发上。 面向对象 Java是一个面向对象的语言。对程序员来说,这意味着要注意其中的数据和...

    毕业设计---基于java的软件资源库的实现(后端).zip

    Java能够自动处理对象的引用和间接引用,实现自动的无用单元收集,使用户不必为存储管理问题烦恼,能更多的时间和精力花在研发上。 面向对象 Java是一个面向对象的语言。对程序员来说,这意味着要注意其中的数据和...

    毕业设计--&gt;物流管理系统的设计与实现(java).zip

    Java能够自动处理对象的引用和间接引用,实现自动的无用单元收集,使用户不必为存储管理问题烦恼,能更多的时间和精力花在研发上。 面向对象 Java是一个面向对象的语言。对程序员来说,这意味着要注意其中的数据和...

Global site tag (gtag.js) - Google Analytics