Java面向對象繼承與組合的問題

Java面向對象繼承與組合的問題
1.繼承和組合的概念
在新類裏簡單地創建原有類的對象。我們把這種方法叫作“組合”,因爲新類由現有類的對象合併而成。我們只是簡單地重複利用代碼的功能,而不是採用它的形式。
第二種方法是創建一個新類,將其作爲現有類的一個“類型”。我們可以原樣採取現有類的形式,並在其中加入新代碼,同時不會對現有的類產生影響。這種魔術般的行爲叫作“繼承”(Inheritance),涉及的大多數工作都是由編譯器完成的。對於面向對象的程序設計,“繼承”是最重要的基礎概念之一。對於組合和繼承這兩種方法,大多數語法和行爲都是類似的(因爲它們都要根據現有的類型生成新類型)。
2.組合也就是一個類的對象是另外一個類的成員,一般的程序都有組合的意味,只不過是基本數據類型是成員變量,下面請看具體的例子
class Head
{
       Head(){
      System.out.println(" head ");
      }
}
class Body
{
      Body(){
      System.out.println(" body ");
      }
}
class Person()
{
      Head h=null;
      Body b=null;
     Person()                                //人是由頭和身體組成的,Head和Body的對象是Person的一部分
    {
      h=new Head();
      b =new Body();
    }
 
}
 
3.繼承作爲面向對象的三個重要特性的一個方面,在面向對象的領域有着及其重要的作用,好像沒聽說哪個面向對象的語言不支持繼承
 class Person
{
 private String name=null;
 private int age=0;
 public Person(String n,int a)
 {
  name=n;
  age=a;
 }
 int getAge()
 {
  return age;
 }
 String getName()
 {
  return name;
 }
 void getDescription()
 {
  System.out.println("name: "+name+"/t"+"age: "+age);
 }
}
class Student extends Person
{
 private String studno=null;
 public Student(String n,String no,int a)
 {
  super(n,a);
  studno=no;
 }
}
說明:Student類中有三個成員變量name,age,studno和一個方法getDescription();
注意:子類繼承了父類的所有變量和函數,只是子類不能訪問父類的private類型的變量和函數,其實privae類型的變量還是繼承到子類中的
 
4.
無論還是繼承,都允許我們將子對象置於自己的新類中。大家或許會奇怪兩者間的差異,以及到底該如何選擇。
如果想利用新類內部一個現有類的特性,而不想使用它的接口,通常應選擇組合。也就是說,我們可嵌入一個對象,使自己能用它實現新類的特性。但新類的用戶會看到我們已定義的接口,而不是來自嵌入對象的接口。考慮到這種效果,我們需在新類裏嵌入現有類的private對象。
有些時候,我們想讓類用戶直接訪問新類的組合。也就是說,需要將成員對象的屬性變爲public。成員對象會將自身隱藏起來,所以這是一種安全的做法。而且在用戶知道我們準備合成一系列組件時,接口就更容易理解。car(汽車)對象便是一個很好的例子:

class Engine {  public void start() {}  public void rev() {}  public void stop() {}}class Wheel {  public void inflate(int psi) {}}class Window {  public void rollup() {}  public void rolldown() {}}class Door {  public Window window = new Window();  public void open() {}  public void close() {}}public class Car {  public Engine engine = new Engine();  public Wheel[] wheel = new Wheel[4];  public Door left = new Door(),       right = new Door(); // 2-door  Car() {    for(int i = 0; i < 4; i++)      wheel[i] = new Wheel();  }  public static void main(String[] args) {    Car car = new Car();    car.left.window.rollup();    car.wheel[0].inflate(72);  }} ///:~

由於汽車的裝配是故障分析時需要考慮的一項因素(並非只是基礎設計簡單的一部分),所以有助於客戶程序員理解如何使用類,而且類創建者的編程複雜程度也會大幅度降低。
如選擇繼承,就需要取得一個現成的類,並製作它的一個特殊版本。通常,這意味着我們準備使用一個常規用途的類,並根據特定的需求對其進行定製。只需稍加想象,就知道自己不能用一個車輛對象來組合一輛汽車——汽車並不“包含”車輛;相反,它“屬於”車輛的一種類別。“屬於”關係是用繼承來表達的,而“包含”關係是用組合來表達的。

5. protected
現在我們已理解了繼承的概念,protected這個關鍵字最後終於有了意義。在理想情況下,private成員隨時都是“私有”的,任何人不得訪問。但在實際應用中,經常想把某些東西深深地藏起來,但同時允許訪問衍生類的成員。protected關鍵字可幫助我們做到這一點。它的意思是“它本身是私有的,但可由從這個類繼承的任何東西或者同一個包內的其他任何東西訪問”。也就是說,Java中的protected會成爲進入“友好”狀態。
我們採取的最好的做法是保持成員的private狀態——無論如何都應保留對基 礎的實施細節進行修改的權利。在這一前提下,可通過protected方法允許類的繼承者進行受到控制的訪問:

import java.util.*;class Villain {  private int i;  protected int read() { return i; }  protected void set(int ii) { i = ii; }  public Villain(int ii) { i = ii; }  public int value(int m) { return m*i; }}public class Orc extends Villain {  private int j;  public Orc(int jj) { super(jj); j = jj; }  public void change(int x) { set(x); }} ///:~

可以看到,change()擁有對set()的訪問權限,因爲它的屬性是protected(受到保護的)。
 
6. 再論合成與繼承
在面向對象的程序設計中,創建和使用代碼最可能採取的一種做法是:將數據和方法統一封裝到一個類裏,並且使用那個類的對象。有些時候,需通過“組合”技術用現成的類來構造新類。而繼承是最少見的一種做法。因此,儘管繼承在學習OOP的過程中得到了大量的強調,但並不意味着應該儘可能地到處使用它。相反,使用它時要特別慎重。只有在清楚知道繼承在所有方法中最有效的前提下,纔可考慮它。爲判斷自己到底應該選用組合還是繼承,一個最簡單的辦法就是考慮是否需要從新類上溯造型回基礎類。若必須上溯,就需要繼承。但如果不需要上溯造型,就應提醒自己防止繼承的濫用。但只要記住經常問自己“我真的需要上溯造型嗎”,對於組合還是繼承的選擇就不應該是個太大的問題
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章