設計模式(二):物件導向及其特性分析

iceWang丶發表於2020-10-22

物件導向

根據大綱,首先我們來學習一種程式碼設計與編寫的風格,即物件導向。

物件導向程式設計和麵向物件程式語言

  • 物件導向程式設計是一種程式設計正規化,通俗來說,就是將 程式碼的組織單元改成類和物件,並將 封裝、繼承、抽象、多型 作為程式碼設計和編寫的基石。
  • 物件導向程式語言代表了能簡易實現物件導向程式設計正規化的語言,其如果能夠用現成的語法機制來實現正規化,就是物件導向程式語言。


從上述的定義中,我們可以看出,物件導向程式設計不一定非要用物件導向程式語言來實現,同時,當我們使用物件導向程式語言來編寫程式碼時,可能寫出來的卻反而是程式導向的程式碼。

物件導向分析和麵向物件設計分別是什麼

既然物件導向程式設計重點是類和物件的實現,那麼針對分析和設計其實就是類和物件該如何設計。


分析講的就是做什麼,而設計講的就是怎麼做。通過這兩個階段產出類的設計,包括該拆出什麼類、每個類有哪些屬性和方法、類和類之間如何互動等。

封裝

定義:封裝的定義是隱藏類中的資訊。通過暴露有限的介面,來保護一些資料,只提供一些開放的介面來完成指定的業務。


實現方式:在 Java 程式碼的實現通過 public、private 等關鍵詞來實現。通過這些關鍵字來確定訪問許可權,從而隱藏對應欄位。


意義:

  • 安全、可控,因為我們指定了哪些屬性是可暴露給外部,哪些是隻能按照指定方式來修改的,因此更加安全可控;
  • 好理解,因為在程式碼的實現裡封裝了多數細節,只暴露一些開放的介面,因此不需要呼叫者太瞭解全部就可以使用了。

抽象

定義:抽象的定義和封裝類似,封裝封的是類內的屬性欄位,抽象抽的是行為的具體實現方式。


實現方式:在 Java 程式碼裡通過 interface 或 abstract class 來實現。但該特性並不是一個物件導向特有特性,只要語言裡有函式的概念,就可以通過多種方式來實現抽象特性。


意義:

  • 因為只暴露方法的定義,因此對使用方來說,不需要關注具體的實現,只面向定義使用即可,內部如何實現以及後續如何更改,只要保證定義不變,使用方就不需要更改;


為了實現上述意義,因此在設計方法定義時,儘量保證方法的定義和具體實現無關,來保證面對需求的修改時可以從容修改。

繼承

定義:繼承好理解了,其實現的是 is-a 的語義,舉個例子來說,設計父類是哺乳動物的話,那麼子類就可以是貓、狗、人等,這些子類都屬於父類的一種。


實現方式:在 Java 程式碼裡繼承是通過 extend 關鍵字來實現的。


意義:繼承最重要的就是解決程式碼複用的問題,即子類複用父類的屬性和方法,避免重複的程式碼編寫多次。




帶來的問題:

  • 多繼承問題,在 Java 裡是沒有多繼承的,因為多繼承會出現菱形問題,導致語義不清,因此官方不允許使用多繼承,即一個子類只可以繼承一個父類。
  • 繼承層次過深,如果繼承的層級結構比較複雜,那麼在想要知道一個類中的某個具體行為實現,可能就需要看很多層級,從而影響程式碼的可讀性和可維護性。


image.png

在 A 中定義了一個方法 test(),類 B 和 類 C 都繼承了A,並對 test() 進行了重寫,此時有個類 D 同時繼承類 B 和類 C,那麼類 D 在呼叫 test() 方法的時候,該呼叫哪一個呢?這就是菱形問題帶來的語義混亂。


組合和繼承:
針對上述所述的問題,因此推薦使用組合的形式來代替繼承,具體的實現方式的話,在後面的文章中再詳細描述。

多型

定義:簡單來說,就是父類指標可以指向子類物件,從而在程式碼實際執行過程中,根據具體是哪一個物件,來決定呼叫哪個物件的方法。


實現方式:文字不好解釋,直接程式碼來解釋。

// 首先定義一個介面
public interface ImageStore {
    void sayHello();
}

// 定義一個類來實現介面,並重寫其中的方法
public class AliyunImageStore implements ImageStore {
    @Override
    public void sayHello() {
        System.out.println("AliyunImageStore say Hello");
    }
}

// 再定義一個類來實現介面,並重寫其中的方法
public class TencentImageStore implements ImageStore {
    @Override
    public void sayHello() {
        System.out.println("TencentImageStore say Hello");
    }
}

// 用介面來指向具體子類,從而呼叫子類的方法
public class Demo {
    public static void main(String[] args) {
        ImageStore aliyun = new AliyunImageStore();
        aliyun.sayHello();

        ImageStore tencent = new TencentImageStore();
        tencent.sayHello();
    }
}

image.png

意義:
提高程式碼的可擴充性,通過父類指標來運算元據,保證在程式碼中實現一個邏輯,可以複用多次。

公眾號截圖




文章在公眾號「iceWang」第一手更新,有興趣的朋友可以關注公眾號,第一時間看到筆者分享的各項知識點,謝謝!筆芯!

相關文章