面試官:淦!0202年你還不知道物件導向?

山禾說發表於2020-06-15

2020年6月13日 多雲轉暴雨⛈️

I'm sad,tired,negative,powerless,miss,lonely fine :)

那你回去等通知吧

面試官:我看你簡歷上說,你的主要程式語言是Java,偶爾也用Python,那麼你可以說一下這兩個的相同點在什麼地方嗎?

山禾:它們都是高階程式設計語言,都是物件導向的語言。

面試官:那你講講你是怎麼理解物件導向的吧。

山禾:emmm。。封裝,繼承,多型是物件導向的三大特徵。

面試官:還有其他要補充的嗎?

山禾:沒了

面試官:那你回去等通知吧

是什麼

痛定思痛,挫折只會讓我變得更強,奧利給!下面開始進入正文,首先我們需要知道物件導向是什麼?

物件導向,顧名思義,是面向物件,也就是說單身狗是不配使用物件導向的程式語言的(當然只是開個玩笑,逃)。

物件,就是把現實世界中的實物對映抽象到虛擬世界中,把實物的屬性和行為,通過程式碼的方式表達出來。然後通過設計物件的資料結構(屬性),然後使用演算法進行行為的模擬(方法),就完成了從現實到虛擬的一個對映。

實體 物件
屬性 資料結構 變數
行為 演算法 方法

與物件導向經常拿來對比的就是程式導向程式設計,那麼他們之間的區別在什麼地方呢?

程式導向和麵向物件

程式導向程式設計,打個比方,我們買過的一般的玩具(變形金剛),我們必須要按照它說明書上的步驟,一步一步的去組裝,才能得到最後的玩具,如果我們想要一個新的玩具,就要去商場買一個新的,然後按照說明書的順序一步一步的組裝。

而物件導向程式設計,就可以理解為積木,沒有一個固定的拼裝方式,我們可以發揮自己的想象力,去自由的拼裝和組裝,同樣的模組在不同的地方可以起到不同的作用(多型),一塊兒積木就是一個最小的單位,我們不用去關心積木是怎麼造的(封裝)。也可以用多個物件組裝起來去拼裝成一個新的物件(繼承)。大大的方便了我們的設計,不再拘泥於過程,極大程度上的放飛了生產力和效率。

為什麼

我們剛剛已經瞭解了物件導向是什麼,下面我們來說一下,為什麼要用物件導向程式設計

  1. 首先從理解角度上來說,它符合我們對現實世界的認知習慣,更容易去理解、實現和設計我們的需求。

  2. 其次從軟體設計的角度上來說,行為的實現對於外部是完全封閉的,只需要提供對應的介面就可以獲得相應的結果,降低了程式碼與程式碼之間的耦合度。符合我們高內聚,低耦合的設計理念。優雅,客觀,層次分明,像積木一樣,可以方便的實現插拔和維護,物件組合而成的模組化和服務化,更是大大擴充套件了系統的伸縮性,便於維護、擴充套件和複用。這也是為什麼越來越多的程式語言選擇向這個方向去靠攏( TypeScript說的就是你

怎麼用

剛剛我一直忍住,沒有去提物件導向的三大特性:封裝、繼承和多型,我相信我們有一些經驗的開發人員來說,這三個詞語是再熟悉不過了。下面,我通過程式碼的方式,來看看這三個特性在程式碼中的模擬應用。

封裝

@Data
public class Uzi {

    // 選手型別
    private String type;
    // 選手最擅長英雄
    private String bestHero;
    // 選手狀態
    private Status status;
    
    public void play() {
        status.say();
    }
}

public class Status {
   public void say(){}
}

上面是一段非常簡單的程式碼,我定義了一個很簡單的類,裡面的nametypebestHero對於我們來說都是一個包裝在盒子裡的東西。比如:

    Uzi uzi = new Uzi();
    uzi.setType("ADC");
    uzi.setBestHero("孫尚香");

我們看到的Uzi可能就是一個主玩孫尚香的職業ADC選手(?狗頭保命,我啥都不知道),他怎麼玩的,我們不需要知道,我們只需要知道他這樣的一名選手就可以了。這就是封裝的魅力:

  1. 隱藏了實現的細節,提供對外的訪問方式。
  2. 外部如果想要訪問,必須經過這個方法。

繼承

看完了封裝,下面我們來看繼承,我們分別用三個狀態去繼承Status類:

public class ShunFeng extends Status {
    
    @Override
    public void say(){
        System.out.println("順風狂小狗");
    }
}
public class NiFeng extends Status {
    
    @Override
    public void say(){
        System.out.println("逆風簡自豪");
    }
}

public class JueJing extends Status {
    
    @Override
    public void say(){
        System.out.println("絕境Uzi");
    }
}

關鍵字extends表示正在構造的新類派生於一個已經存在類。這個已經存在的類被稱為父類(超類,基類);新建立的類被稱為子類。在通過擴充套件父類定義子類的時候,僅僅需要指出子類和父類的不同之處。因此在設計類的時候,應該將通用的方法放在父類中,而將具有特殊用途的方法放在子類中。

我們只是在父類Status中定義了say方法,然後三種不同的類去繼承這個類,然後實現方法,這樣就體現出了物件導向在設計上的可擴充套件性,但是需要注意的是,繼承會破壞封裝,我們需要謹慎使用,儘量使用一些設計模式去避免繼承,合理使用,才能體現出它的優勢~

說完了繼承,接下來就要去說多型了。

多型

在說多型之前,我們先來看一下程式碼:

public class Test {
    public static void main(String[] args) {
        //uzi1
        Uzi uzi1 = new Uzi();
        ShunFeng shunFeng = new ShunFeng();
        uzi1.setStatus(shunFeng);
        //uzi2
        Uzi uzi2 = new Uzi();
        NiFeng niFeng = new NiFeng();
        uzi2.setStatus(niFeng);
        //uzi3
        Uzi uzi3 = new Uzi();
        JueJing jueJing = new JueJing();
        uzi3.setStatus(jueJing);
        
        //uzis
        Uzi[] uzis = {uzi1,uzi2,uzi3};
        // 多型
        for (Uzi uzi : uzis) {
            uzi.play();
        }
    }
}

執行程式的結果: (TMD,淚目,?青結)

所謂的多型就是一個物件變數(比如上文中的status變數)可以指示多種實際型別的現象(比如status既可以引用Status物件,也可以引用它的子類ShunFeng物件)被稱為多型。在執行時候能夠自動地選擇呼叫哪個方法的現象被稱為動態繫結,上面列印出的語句,就說明了這一點。

後續

原來我們天天掛在口邊的物件導向,其實某種程度上來說,更像是一種哲學,一種電腦科學發展的自然規則。

如果你有學到,請給我點贊?+關注,這是對一個✊堅持原創作者的最大支援!我是山禾,千篇一律的皮囊,萬里挑一的靈魂,一個不太一樣的寫手。

世事洞明皆學問,人情練達即文章。

相關文章