知識點---(組合(Composition)VS (inheritace)繼承)

組合(Composition)VS 繼承(inheritace)
組合和繼承是實現“重複運用classes”的兩種方法,各自有自己優劣,在程序的設計中如何靈活高效地運
用這兩種方法對每個人來講都是一個值得研究的問題;在《TIJ》中有這樣寫到:“當你想要在新的class中
使用既有的class的功能,而非其接口,通常你選擇組合是正確的,就是說,嵌入某個對象,使你得以在新的class
中以它實現你想要的功能。但是新class的使用者只能看到你爲新class所定義的接口,不會看到內嵌的那個對象的
接口。但是如果這正是你希望的,你應該在新的class中以private形式嵌入既有的classes的對象”
+------Composition Example----------------------------------------+
class  A
{
  private int i;
  Private void Test(int i){
  System.out.println("i = "+i);
 }
 public static void main(String[] args)
 {
 System.out.println("A");
  }
}
public class B
{
  private static  A a = new A();//嵌入成員對象
  public static void main(String[] args)
{
  B b = new B()
  //b.Test(3)------->不能這樣調用,
  a.Test(3);//通過a來調用class中是Test()
  System.out.println("b");
 }
}
+---------Inheritance Example-------------------------------------+
class  A
{
  private int i;
  Private void Test(int i){
  System.out.println("i = "+i);
  }
 public static void main(String[] args)
 {
 System.out.println("A");
  }
}
public class B extends A
{
  private static  A a = new A();//嵌入成員對象
  public static void main(String[] args)
 {
  B b = new B()
  b.Test(3)//通過繼承,可以直接以derived class的對象來調用base class的方法
  a.Test(3);//通過a來調用class中是Test()
  System.out.println("b");
 }
}
+----------------------------------------------------------------End--+
繼承最重要的並不是爲新的class提供函數,而是繼承可以實現向上轉型(upcasting)。在OOP的學習過程中常常
強調繼承,但是並不代表你應該處處使用它。在《爲什麼extends是有害的》裏面對extends帶來的種種壞處有詳細
的描述,“大多數好的設計者象躲避瘟疫一樣來避免使用實現繼承(extends 關係)。%80的代碼應該完全用interfaces
寫,不用具體的基類。”有人問Jams Gosling:“如果你重新構造Java,你想改變什麼?”。“我想拋棄classes”他回答
他解釋說:真正的問題不是由於class本身,而是實現繼承(extends 關係)。接口繼承(implements關係)是更好的。你應
該儘可能的避免實現繼承。(對於implemments和extends的比較現在就不細究了。再回到組合與繼承上來)對於繼承的使用
其必須是能產生明顯的實用價值。如果你必須將新的class向上轉型爲base class,你就應該用繼承,如果向上轉型不是必須
的,那麼你就要仔細考慮是否要動用繼承。講到向上轉型,問題又來了,爲什麼要向上轉型呢?最具競爭力的答案就是-----
多態(polymorphism):數據抽象化(Data abstraction),繼承(Inheritance)和多態(Polymorphism)是面向對象鞭策語言
的三個核心本質。爲什麼要向上轉型呢,看看下面的例子:
+-----------------------Upcast why--------------------------------------------+
First:Polymorphism.java
class Animal
{
 void breathe(){
  System.out.println("Animal.breathe");
 } 
}
class Human extends Animal
{
 void breathe(){
  System.out.println("Human.breathe");
 }
}
class Dog extends Animal
{
 void breathe(){
  System.out.println("Dog.breathe");
 }
}
class Cat extends Animal
{
 void breathe(){
  System.out.println("Cat.breathe");
 }
}
public class Polymorphism
{
    public static void Upcast(Animal a){//<----Notice
  a.breathe();
}
    public static void main(String args[]){
  Human h = new Human();
  Dog d = new Dog();
  Cat c = new Cat();
  //--Upcasting---
  Upcast(h);
  Upcast(d);
  Upcast(c);
 }
}//end
---------------------
Second Polymorphism_1.java
class Animal
{
 void breathe(){
  System.out.println("Animal.breathe");
 }
 
}
class Human //extends Animal
{
 void breathe(){
  System.out.println("Human.breathe");
 }
}
class Dog //extends Animal
{
 void breathe(){
  System.out.println("Dog.breathe");
 }
}
class Cat //extends Animal
{
 void breathe(){
  System.out.println("Cat.breathe");
 }
}
public class Polymorphism_1
{
    public static void Upcast(Human a){//<----Notice
  a.breathe();
 }
    public static void Upcast(Dog a){//<----Notice
  a.breathe();
 }
 public static void Upcast(Cat a){//<----Notice
  a.breathe();
 }
    public static void main(String args[]){
  Human h = new Human();
  Dog d = new Dog();
  Cat c = new Cat();
  //--No Upcasting---
  Upcast(h);
  Upcast(d);
  Upcast(c);
 }
}//end
+-----------------------------------------------------------------end
如果不向上轉型,你就得爲每一個新的class撰寫一個相應的Upcast(),這不僅在開始寫代碼的時候很花功夫,另外如果
你想加入新的class,你還得增加類似的函數。(很費力的哦!)。 爲什麼在第一個例子Polymorphism.java裏面。向上轉型
後的不同對象會正確的調用各自的方法呢?這裏就又涉及到Method-call綁定方式:後期綁定(late binfing/run-time binding
or dynamic binding,名字還真多!),具體這裏就不多說了。

 


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章