1. 程式人生 > >Java 學習(三)—— 面向物件

Java 學習(三)—— 面向物件

一、面向過程的思想和麵向物件的思想

    (1)面向過程是一種思維方式。當試圖通過面向過程解決問題時,我們的關注點在於問題解決的流程,重在這個過程的控制,需要用大量的模組(模組化的思想源自於硬體,在C語言中是函式)將大問題拆解,程式設計師通過控制模組的執行順序以解決問題。

    舉個例子,當我們解決一個“如何將大象裝入冰箱?”的問題時,最簡單的解決思路是面向過程解決: 
    1、關注過程,將大問題拆解為小問題,實現每個小問題的解決方法 
    a、開啟冰箱門 
    b、將大象裝入冰箱 
    c、關閉冰箱門 
    2、通過控制程式碼,控制模組執行,執行順序為a->b->c,問題解決。

在日常生活或者說日常程式設計中,簡單的問題用面向過程的思路解決,更加直接有效,但是當問題的規模稍大時,如要描述三萬個人吃飯的問題,或者要構建一個航空母艦模型的時候,用面向過程的思想是遠遠不夠的。而且面向過程程式的程式碼複用性、可擴充套件性、可移植性、靈活性、健壯性都會在處理大規模問題中出現問題。

    (2)面向物件最基本的要素就是抽象。比如剛剛提到的描述三萬人吃飯的問題,首先要解決的是三萬個人描述的問題,三萬個人都是人,有鼻子有眼,都要吃飯,那我們把“人”抽象出來,他們的共性就提取出來了,描述起來就容易太多了。每個人的差異交給繼承多型去做吧。而吃飯的過程就很簡單了,用面向過程的思想解決就好了,所以面向物件是建立在面向過程基礎上解決問題的,面向物件更適合解決較複雜的問題。

剛剛提到的構建航空母艦模型的問題,面向過程肯定是不行的。而用面向物件也有一定問題,因為一個航空母艦是由太多太多元件構成的,每個元件都是一個物件的話,那麼程式需要控制太多物件,而物件和物件的依賴關係也極其複雜,再通過程式控制物件的生命週期就不現實了。這時我們就想如果有一個靠譜的第三方為為我們管理物件就好了,這就出現了大名鼎鼎的spring了,它通過將物件的依賴關係存入xml中,在我們需要某個物件的時候,spring容器為我們建立,並將物件間的依賴關係注入(依賴注入)。物件的控制權由程式轉向了spring容器,也就是IOC(控制反轉)。

       

區別:作為面向物件的思維來說,當你拿到一個問題時,你分析這個問題不再是第一步先做什麼,第二步再做什麼,這是面向過程的思維,你應該分析這個問題裡面有哪些類和物件,這是第一點,然後再分析這些類和物件應該具有哪些屬性和方法。這是第二點。最後分析類和類之間具體有什麼關係,這是第三點。

      面向物件有一個非常重要的設計思維:合適的方法應該出現在合適的類裡面

二、簡單理解面向物件

  就是在程式裡面首先分解出來的應該是注意不再是一步一步的過程了,而是首先考慮在這個問題域裡面或者程式裡面應該具有有哪些物件,所以從現在開始考慮任何問題腦子裡不要再想著我實現這件事我第一步應該幹什麼,第二步應該幹什麼,如果這樣想,那就是面向過程的思維了。面向物件的思維是,當我碰到這個問題域的時候,碰到這個程式的時候,我首先應該把這個問題裡有哪些物件,物件與物件之間有什麼關係抽象出來。

三、面向物件的設計思想

  面向物件的基本思想是,從現實世界中客觀存在的事物出發來構造軟體系統,並在系統的構造中儘可能運用人類的自然思維方式。

  面向物件更加強調運用人類在日常生活的邏輯思維中經常採用的思想方法與原則,如抽象、分類,繼承、聚合、多型等。

  人在思考的時候,首先眼睛裡看到的是一個一個的物件。

四、物件和類的概念

     物件是用於計算機語言對問題域中事物的描述,物件通過“屬性(attribute)”和“方法(method)”來分別對應事物所具有的靜態屬性和動態屬性

     類是用於描述同一類的物件的一個抽象的概念,類中定義了這一類物件所具有的靜態屬性和動態屬性

    類可以看成一類物件的模板,物件可以看成該類的一個具體例項

    eg.什麼叫瓶子?

     瓶子的定義:具有某些類特徵的東西就是瓶子,比分說什麼樣的形狀,比方說有個口,能倒水,能裝水,一般有個蓋等等。給瓶子下定義的過程,其實就是把瓶子裡的某些東西抽象出來了,所以瓶子在這裡是叫做一類事物的一個抽象,在你腦子裡有瓶子的概念,可瓶子的概念在你腦子裡到底是什麼呢?瓶子的概念在你腦子裡叫做一類事物的一個抽象。怎麼抽象的呢?你往往抽象的是這兩個方面:第一個方面我們叫它靜態的屬性,瓶子應該具有哪些特徵,比分說瓶子應有個口,這是它的具有的一個靜態屬性,瓶子一般有一個蓋,這也是它的具有一個靜態屬性,除此之外,你還可能給它總結動態的屬性,什麼動態的屬性呢?比放說瓶子能倒水,這是它的動態屬性。瓶子這個概念在你腦子裡如果你細細的思維的話,其實你給它做了兩方面的總結,一方面是靜態的,一方面是動態的。反映到JAVA的類上,一個就是成員變數(靜態屬性),一個就是方法(動態屬性)方法是可以執行的,可以動的。成員變數是某一個類的靜態屬性。所以你腦子裡瓶子的概念實際上是一類事物的一個抽象,這種東西我們叫它類,椅子是類,桌子是類,學生是類。什麼是物件呢?這一類事物的具體的某個例項就叫做物件。所以一類事物的具體的某一個東西,符合這類事物具體的特徵的某個東西就叫做物件。瓶子是一個類,某個瓶子就是瓶子這個類裡面的一個物件。

五、如何抽象出一個類?

       有兩個方面,一方面是它的靜態屬性,另一方面是它的動態屬性。反映到JAVA裡面的類怎麼包裝它呢?一方面成員變數,另一方面是方法。

  eg.職員這個類該怎麼抽象出來?也是從兩個方面,一方面是它的靜態屬性,另一方面它的動態屬性

  職員有哪些屬性呢?有姓名,年齡,目前工資數額等屬性,他有哪些方法呢?讓這個職員來顯示姓名,顯示年齡,修改姓名,領取工資。當然顯示姓名,顯示年齡,修改姓名,領取工資這些也可以讓別人來做,但面向物件的設計思維是最合適的方法應該出現在最合適的類裡面。顯示姓名,顯示年齡,修改姓名,領取工資由誰來做更合適呢,那就是職員自己最合適。所以這些方法應該出現在職員這個類裡面。

  對於類來說,它有一些屬性或者稱為成員變數,以後說屬性或者成員變數指的是同一回事。具體的物件他有沒有相關的一些屬性或者叫成員變數呢?有,每一個人都有一份,只不過是取值不同而已。如從職員這個類例項化出來的兩個職員:職員A和職員B,他們都有姓名,年齡,目前工資數額這些屬性,但他們的名字,年齡,領取的工資數額都不一樣。這樣就能把職員A和職員B區分開來了,正是因為他們的屬性值不一樣,所以這個物件才能和另外的物件區分開來,所以通過屬性是可以區分兩個物件的。貓是一個類,這隻貓是一個物件,這隻貓和另外一隻貓該怎麼區分開來呢?那就得看你的貓這個類是怎麼定義的了,貓有貓毛,毛有顏色。OK,這隻貓是黑貓,另一隻貓是白貓,這樣通過貓毛的顏色區分開來了。如果只定義一個,如捉老鼠,白貓也能捉,黑貓也能捉,這樣就沒辦法區分出黑貓和白貓了,所以根據方法是沒辦法區分兩個物件的。所以每個物件都有自己的屬性,屬性值和另外一個物件一般是不一樣的

  一定要區分類和物件,什麼叫做類?什麼叫做物件?類是一類事物的一個抽象,具有共同特徵的一類事物的一個抽象。物件是這個類具體的某一個例項,所以以後說例項(instance)或者說物件(object)指的是同一回事。

六、類(物件)之間的關係

一.關聯關係(最弱的一種關係)

  類和類之間是有關係的,如學生和老師這兩個類,老師可以教學生,學生可以向老師學習。這就是他們之間的關係。關係和關係之間是不同的,你和你老婆的關係和你和你其他女朋友的關係是不能混為一談的。關係最弱的一種關係叫關聯關係。關聯關係反應到程式碼上往往是一個類的方法裡面的引數是另一個類的具體的某一個物件,比如教授教研究生,教哪個研究生,教是教授這個類裡面的一個方法,某個研究生是研究生這個類裡面的一個具體的物件。關聯關係是最弱的一種關係,咱們兩個類之間有關係,或者兩個物件之間有關係,但關係不是很緊密。

二.繼承關係(比較強的一種關係)

  繼承關係封裝了這樣一種邏輯:“XX是一種XX”,只要這東西能說通了,就可以考慮用繼承關係來封裝它。如:游泳運動員從運動員繼承,游泳運動員是一種運動員,這能說得通,所以游泳運動員就是從運動員繼承過來的,游泳運動員和運動員就是一種繼承關係。學生是一個人,學生從人繼承,老師是一個人,老師也從人繼承,學生是一種老師,這說不通,所以學生和老師就不存在繼承關係。所以將來做設計的時候要分清繼承關係很簡單,你只要說通這麼一句話:“XX是一種XX”。OK,那他們之間就是繼承關係。籃球運動員是一種球類運動員,這說得通,所以籃球運動員從球類運動員繼承,這樣繼承很有可能會產生一棵繼承樹,運動員派生出來,派生出來的意思是游泳運動員這個類、球類運動員這個類、射擊運動員類從它繼承,相當於運動員派生出來了這些個不同的運動員,包括游泳的,球類的,射擊的。球類的再派生足球的,籃球的,排球的。這就是一棵繼承樹,不過這棵樹是比較理想化的情況,只有一個根節點。但實際當中,我們真實世界當中的繼承關係不一定只從一個類繼承,一個類可能從多個類繼承過來,比如說:金絲猴從動物這個類繼承,這很正常,但我還有另外一個專門的類:“應該受到保護的東西”,這也是一個類,金絲猴應該受到保護,所以金絲猴是一種應該受到保護的東西。所以金絲猴從“應該受到保護的東西”這個類繼承過來。所以在現實情況當中,一個類完完全全有可能從多個不同的類繼承,C++正是因為想封裝這種繼承關係,所以C++存在多重繼承。

三.聚合關係(整體和部分)(比較強的一種關係)

  什麼是聚合?聚合就是一個整體與部分的關係。我們說“XX是XX的一部分”,只要說得通,那麼他們之間的關係就是聚合關係,隊長是球隊的一部分,隊員是球隊的一部分。所以隊長和球隊是聚合關係,隊員和球隊也是聚合關係。腦袋是人的以部分,身體和胳膊也是人的一部分,因此腦袋,身體和胳膊與人都是聚合關係。聚合關係分得再細一點的話就可以分成聚集關係和組合關係,比如球隊、隊長,隊員,這三者是聚集關係,假如這個隊長既是足球的隊長,同時也是籃球的隊長,一個人分屬兩個不同的球隊,這是可以的,球隊與隊長之間沒有我離不了你,你離不了我這種情況,所以如果分得更細的話,這種就叫做聚集關係。還有一種情況叫組合,組合說的是咱們倆密不可分,我是你必不可少的一部分。一個人的腦袋不可能既屬於你又屬於別人,身體也一樣,不可能既屬於你又屬於別人。所以你的身體,腦袋和你是密不可分的,這是一種更加嚴格的聚合關係,專門給它取了個名字叫組合。

四.實現關係

  作為父類來說,我覺得我應該具有這樣一個方法,但我不知道怎麼去實現,誰去實現,我的子類去實現,這就是實現關係。和實現關係息息相關的還有一種關係叫多型。

五.多型

七、Java與面向物件

  物件和類是分不開的,必須首先定義類才能有物件。首先定義方法才能呼叫。物件是JAVA裡面的核心,做任何東西你首先都得給我造出一個物件才能做。靜態屬性簡稱屬性,也叫成員變數,以後說屬性或者說成員變數它們指的都是同一回事。

  整個類可以看作是靜態的屬性還有方法他們之間的一個綜合。怎麼抽象出一個類的概念,還是那句話,你必須抽象出兩個方面來,第一方面是看他們的靜態屬性,他們有哪些成員變數,第二方面是看他們的有哪些方法。

  寫JAVA程式時,我們一上來寫的就是public class(宣告一個類),在這個class裡面我們寫的是成員變數和方法。

  每一個JAVA裡面的class(類)都對應了我們現實生活中某一類事物的一個抽象。比如說要在JAVA裡面封裝一隻狗,具體怎麼封裝,如何寫程式碼,程式碼如下:

package cn.javastudy.summary;
/**
 * 一類事物封裝到JAVA裡面首先得寫class,定義這個類,類名是什麼可以自己取。
 * 這裡把類名叫做Dog
 */
public class Dog {
    /**
     * 接下來就是寫這個狗這個類的屬性或者叫成員變數,
     * 比如說狗這個類的毛的顏色,怎麼定義這個屬性呢,
     * 首先得定義毛的一個型別,如使用int來定義毛的顏色型別
     */
    int furcolor; //定義屬性:毛的顏色
    float height; //定義屬性:狗的高度
    float weight; //定義屬性:狗的體重
    
    /**
     * 狗的顏色,高度,體重這些屬性定義完了,接下來要定義的就是方法了。
     * 如寫一個CatchMouse()方法,捉老鼠的方法。
     * CatchMouse這個方法裡面有一個物件型別的引數,捉哪一隻老鼠,這個物件引數是屬於Mouse這個類的
     * @param m
     */
    void CatchMouse(Mouse m){
            //在方法體內寫捉老鼠這個過程,怎麼捉,跑著捉,走著捉
            System.out.println("我捉到老鼠了,汪汪!,老鼠要尖叫了!");
            /**
             * 老鼠尖叫一聲,表示被狗咬到了,咬到了能不叫嗎,很自然而然地想到,
             * 尖叫(scream())這個方法是屬於Mouse這個類裡面的某一個方法。
             * 老鼠自己呼叫它,讓它自己尖叫。這就是面向物件的思維。
             */
            m.scream();
    }
    
    public static void main(String[] args) {
        Dog  d = new Dog();//首先用new關鍵字建立一隻狗
        Mouse m=new Mouse();//造出一隻老鼠。
        d.CatchMouse(m);//然後用這隻狗去抓老鼠,讓狗呼叫CatchMouse()方法去捉某隻老鼠。
    }
}
package cn.javastudy.summary;
/**
 * 封裝的老鼠類
 */
public class Mouse {
    /**
     * 老鼠自己有一個發出尖叫的方法
     * 當被狗咬到時就會發出尖叫
     */
    public void scream() {
        System.out.println("我被狗咬到了,好痛啊!");
    }

}

     從這個意義上來講,JAVA裡面的每定義一個類實際上就相當於一種新的資料型別。就跟int ,float, String等一樣,不過是一種新定義的型別而已。

八、為什麼使用面向物件程式設計?

  面向物件程式設計:一組物件互相配合通過溝通完成特定功能

  做軟體苦苦追求的一種境界是可重用性(reusable),可擴充套件性。如果是面向過程,一般情況是屬性和方法它們是分開的,他們不是聚合的關係,不是合在一起的,這樣要複用起來比較麻煩,複用的層次只是侷限於方法這個層次上,而面向物件則不同,它是把屬性和方法綜合在一個裡面。綜合在一起復用的時候是整個物件進行復用。所以面向物件和麵向過程相比,前者更加容易讓我們達到可重用性。