Java-Choose between Composition and Inheritance
2008-03-29 18:13
393 查看
先介绍两个概念
增量开发
继承技术的优点之一就是它支持增量开发模式. 你可以引入新代码(包括覆盖基类代码)而不会在现有代码中引发bug; 事实上, 这种模式可以将新的bug隔离在新的代码之中.
即使出现bug, 也知道它是在新代码中, 易于差错.
切记: 继承代表着对一种关系的展示, 即"此新类是彼旧类的一种类型".
向上转型
"为新类提供方法"并不是继承技术中最重要的方面, 其最重要的方面是用来表现新类和基类之间的关系. 这种关系可以用"新类是现有类的一种类型"这句话加以概括.
由于继承意味着基类中所有的方法在导出类中也同样有效, 所以能够向基类发送的所有消息同样也可以向导出类发送.
由于向上转型是从一个较专用类型向较通用类型转换, 所以总是安全的. 也就是说, 导出类是基类的一个超集. 它可能比基类含有更多的方法, 但它至少具备基类中含有的所有方法.
在向上转型的过程中, 类接口中唯一可能发生的事情是丢失方法, 而不是获取它们. 这就是为什么编译器在"未曾明确表示转型"or"未曾指定特殊标记进行转型"的情况下, 仍然允许向上转型的原因.
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedBlock.gif)
/** *//**
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
* Title: Inheritance & Upcasting<br>
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
* Description: 此例解释"向上转型"概念, 无任何功能接口<br>
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
* Copyright: (c) 2008 Thinking in Java<br>
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
* Company: Augmentum Inc
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
* @author Forest He
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
* @version 1.0
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif)
*/
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedBlock.gif)
class Instrument ...{
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedSubBlock.gif)
public void play() ...{ System.out.println("Upcasting: 目前运行的方法是基类方法play(), 基类方法tune()利用基类对象调用了play()"); }
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedSubBlock.gif)
public static void tune(Instrument i) ...{ i.play(); }
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif)
}
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedBlock.gif)
class Wind extends Instrument ...{
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedSubBlock.gif)
public static void main(String[] args) ...{
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
Wind flute = new Wind();
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
Instrument.tune(flute);
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif)
}
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedBlock.gif)
/**//* 上例中, tune()方法接受Instrument引用. 但在Wind.main()中, tune()方法是通过一个Wind引用而被调用的.
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
* 鉴于Java对类型检查十分严格, 接受某种类型的方法同样可以接受另外一种类型就会显得很奇怪, 除非你认识到Wind对象同样也是一种Instrument对象.
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
* 在tune()中, 程序代码可以对Instrument和它的所有导出类起作用, 这种将Wind引用转换为Instrument引用的动作, 我们称之为"向上转型".
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif)
*/
Choose between Composition and Inheritance
组合和继承都允许在新类中放置子对象, 组合是显式地这么做, 而继承则是隐式地做.
组合技术通常用于想在新类中使用现有类的功能而非它的接口这种情形. 但新类用户希望看到的只是为新类所定义的接口, 而非嵌入对象的接口. 为取得此效果, 需要将新类中嵌入的现有类对象设置为private.
"is-a"(是一个)的关系是用继承来表达的, 而"has-a"(有一个)的关系则是用组合来表达的.
在OO编程中, 生成和使用程序代码最有可能采用的方法就是直接将数据和方法包装进一个类中, 并使用该类的对象. 也可以运用组合技术使用现有类来开发新的类; 而继承技术实际是不太常用的.
应当慎用继承技术, 其使用场合仅限于你确信使用该技术确实有效的情况. 到底是该用Composition还是Inheritance, 一个最清晰的判断方法就是问一问自己是否需要从新类向基类进行向上转型. 如果需要Upcasting, 则Inheritance是必要的; 但如果不需要, 则应当好好考虑自己是否需要继承.
增量开发
继承技术的优点之一就是它支持增量开发模式. 你可以引入新代码(包括覆盖基类代码)而不会在现有代码中引发bug; 事实上, 这种模式可以将新的bug隔离在新的代码之中.
即使出现bug, 也知道它是在新代码中, 易于差错.
切记: 继承代表着对一种关系的展示, 即"此新类是彼旧类的一种类型".
向上转型
"为新类提供方法"并不是继承技术中最重要的方面, 其最重要的方面是用来表现新类和基类之间的关系. 这种关系可以用"新类是现有类的一种类型"这句话加以概括.
由于继承意味着基类中所有的方法在导出类中也同样有效, 所以能够向基类发送的所有消息同样也可以向导出类发送.
由于向上转型是从一个较专用类型向较通用类型转换, 所以总是安全的. 也就是说, 导出类是基类的一个超集. 它可能比基类含有更多的方法, 但它至少具备基类中含有的所有方法.
在向上转型的过程中, 类接口中唯一可能发生的事情是丢失方法, 而不是获取它们. 这就是为什么编译器在"未曾明确表示转型"or"未曾指定特殊标记进行转型"的情况下, 仍然允许向上转型的原因.
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedBlock.gif)
/** *//**
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
* Title: Inheritance & Upcasting<br>
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
* Description: 此例解释"向上转型"概念, 无任何功能接口<br>
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
* Copyright: (c) 2008 Thinking in Java<br>
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
* Company: Augmentum Inc
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
* @author Forest He
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
* @version 1.0
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif)
*/
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedBlock.gif)
class Instrument ...{
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedSubBlock.gif)
public void play() ...{ System.out.println("Upcasting: 目前运行的方法是基类方法play(), 基类方法tune()利用基类对象调用了play()"); }
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedSubBlock.gif)
public static void tune(Instrument i) ...{ i.play(); }
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif)
}
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedBlock.gif)
class Wind extends Instrument ...{
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedSubBlock.gif)
public static void main(String[] args) ...{
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
Wind flute = new Wind();
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
Instrument.tune(flute);
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif)
}
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedBlock.gif)
/**//* 上例中, tune()方法接受Instrument引用. 但在Wind.main()中, tune()方法是通过一个Wind引用而被调用的.
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
* 鉴于Java对类型检查十分严格, 接受某种类型的方法同样可以接受另外一种类型就会显得很奇怪, 除非你认识到Wind对象同样也是一种Instrument对象.
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
* 在tune()中, 程序代码可以对Instrument和它的所有导出类起作用, 这种将Wind引用转换为Instrument引用的动作, 我们称之为"向上转型".
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif)
*/
Choose between Composition and Inheritance
组合和继承都允许在新类中放置子对象, 组合是显式地这么做, 而继承则是隐式地做.
组合技术通常用于想在新类中使用现有类的功能而非它的接口这种情形. 但新类用户希望看到的只是为新类所定义的接口, 而非嵌入对象的接口. 为取得此效果, 需要将新类中嵌入的现有类对象设置为private.
"is-a"(是一个)的关系是用继承来表达的, 而"has-a"(有一个)的关系则是用组合来表达的.
在OO编程中, 生成和使用程序代码最有可能采用的方法就是直接将数据和方法包装进一个类中, 并使用该类的对象. 也可以运用组合技术使用现有类来开发新的类; 而继承技术实际是不太常用的.
应当慎用继承技术, 其使用场合仅限于你确信使用该技术确实有效的情况. 到底是该用Composition还是Inheritance, 一个最清晰的判断方法就是问一问自己是否需要从新类向基类进行向上转型. 如果需要Upcasting, 则Inheritance是必要的; 但如果不需要, 则应当好好考虑自己是否需要继承.
相关文章推荐
- Multiple Inheritance in Java and Composition vs Inheritance
- thinking in java(V)--composition and inheritance
- Difference between Association, Composition and Aggregation in Java, UML and Object Oriented Program
- Thinking in Java(6)-combinning composition and inheritance
- the differences between groovy and java
- Difference between transient and volatile keyword in Java
- JavaScript closure: difference between call and apply as well as use them to create inheritance
- Java-convert between INT and STRING
- Thinking in Java(8)-inheritance and cleanup
- 9 Differences between TCP and UDP Protocol-Java Network Interview Question-译文
- Difference between List and Set in Java Collection
- Java – Convert date and time between timezone
- Borland Eyeing the Chasm Between Java and .NET
- Differences between C++ and Java
- Java Wish List: The Top Differences Between Java, Scala, Groovy, Clojure and Kotlin
- Difference between Composition and Aggregation
- Necessitas: convenient solution for communication between Qt application and Java
- Java-What is the difference between <? super E> and <? extends E>?
- "Integration" between Rails' ActiveRecord and Java's Hibernate - Stack Overflow
- Java - Difference between Stack and Heap memory in Java