繼承實現了代碼的複用,抽象類別兼顧了代碼複用與實現多態的目的,介面是一個100%的抽象類別,它的存在則純粹是為了多態。
多態,範例程式碼如下:
public abstract class Animal { int size; public abstract void makeNoise(); public abstract void sleep(); } public class Cat extends Animal { public void makeNoise() { System.out.println("miao! miao!"); } } public class Dog extends Animal { public void makeNoise() { System.out.println("wang! wang!"); } }
以上是3個類, Dog 和 Cat 繼承自 Animal,下邊寫一個針對這三個類的測試類別。
public class TestMain { public static void main(String[] args) { TestMain testMain = new TestMain(); Dog dog = new Dog(); Cat cat = new Cat(); testMain.runAnimalMakeNoise(dog); // dog引用變數是Dog類型的,Dog繼承自Animal testMain.runAnimalMakeNoise(cat); // cat引用變數是Cat類型的,Cat繼承自Animal } public void runAnimalMakeNoise(Animal animal) //這個方法以Animal類型的引用變數作為參數,然而如果利用多態,我們可以傳入任意Animal類的子類型引用變數作為參數 { animal.makeNoise(); //不管實際傳入的參數是什麼類型,只要它繼承自Animal,它就會有makeNoise這個方法。 } }
運行後輸出為:
wang! wang!
miao! miao!
從上邊測試類別中可以看出,即使再增加一些其他繼承自 Animal 的類比如 Duck 等,runAnimalMakeNoise方法依然有效。多態對於介面而言,如果定義個一個介面類型的引用變數,這個引用變數可以被賦予任意一個實現了此介面的對象,而不用管此對象自身實際繼承自哪裡。
面向介面編程:這裡的介面不單單指的是JAVA的那個關鍵字interface,面向介面編程應該理解為面向超類編程,面向介面編程的思想正是利用了多態的特性,可以讓寫出的程式具有很強的擴充性與可維護性。 面向介面編程一般指在類的執行個體變數,類方法的參數,類方法的傳回值類型等地方應用多態進行編程。 用設計模式中的策略模式舉例(參考自《head first design pattern》):
一個沒有應用策略模式的程式碼片段:
public abstract class Duck { public abstract void fly(); }
應用策略模式以後上邊的代碼變為如下形式。
public abstract class Duck { FlyBehavior flyBehavior; // FlyBehavior 是一個介面,只有一個fly方法, 這裡利用多態,使 flyBehavior 可以被賦予 // 任意一個實現了FlyBehavior介面中fly方法的類。這樣我們可以更改鴨子類的飛的行為而不用 // 變動原先的代碼,只需要將不同的實現了FlyBehavior 介面的類賦予 flyBehavior 就可以了。 public void performFly() { flyBehavior.fly(); } // 這裡 performFly方法相當於上邊沒有應用策略模式代碼中的 fly方法,只是這裡我們把飛的 // 這個行為委託給了flyBehavior來執行。 public void setFlyBehavior(FlyBehavior fb) { flyBehavior = fb; } // 這個的方法的好處在於,可以在程式運行中動態改變鴨子飛的行為,只需要將不同的實現了 // FlyBehavior 介面中 fly方法的類賦給 flyBehavior引用變數即可。 } public interface FlyBehavior // 這個介面定義了鴨子飛的行為,接下來由不同的類來實現此介面,並 // 實現不同的fly方法賦值給 Duck類型對象中的flyBehavior引用變數。 { public void fly(); } public class SlowFly implements FlyBehavior // 實現FlyBehavior 介面,定義了一個慢慢飛的行為 { public void fly() // 實現介面中抽象的fly方法。 { System.out.println("我飛得慢"); } } public class FastFly implements FlyBehavior // 實現FlyBehavior 介面,定義了一個飛的快的行為 // SlowFly 和 FastFly類型的對象都可以賦值給Duck類或子類中 // 的 flyBehavior 引用變數,來改變鴨子飛的行為,如果鴨子飛 // 的行為需要改變只需要再建立一個類實現不同的fly方法即可。 { public void fly() // 實現介面中抽象的fly方法。 { System.out.println("我飛得快"); } }
Duck類的子類:
public class SpecialDuck extends Duck { public SpecialDuck() { this.flyBehavior = new SlowFly(); } }
測試類別:
public class TestMain { public static void main(String[] args) { SpecialDuck sd = new SpecialDuck(); // 預設在SpecialDuck的建構函式中把飛的慢的行為賦值給了flyBehavior sd.performFly(); //輸出“我飛得慢” FastFly ff = new FastFly(); //建立一個飛得快的行為執行個體 sd.setFlyBehavior(ff); //將飛得快的行為執行個體在程式運行時動態賦值給SpecialDuck 的 flyBehavior執行個體變數。 sd.performFly(); //輸出“我飛得快” } }
運行後輸出:
我飛得慢
我飛得快
策略模式定義了一組針對相同行為的不同演算法,分別封裝起來,這樣可以讓演算法的變化獨立於使用演算法的類。多態用處soso。。