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的過程中得到了大量的強調,但并不意味着應該盡可能地到處使用它。相反,使用它時要特别慎重。隻有在清楚知道繼承在所有方法中最有效的前提下,才可考慮它。為判斷自己到底應該選用組合還是繼承,一個最簡單的辦法就是考慮是否需要從新類上溯造型回基礎類。若必須上溯,就需要繼承。但如果不需要上溯造型,就應提醒自己防止繼承的濫用。但隻要記住經常問自己“我真的需要上溯造型嗎”,對于組合還是繼承的選擇就不應該是個太大的問題 |