如何理解「面向對象」編程思想

理解面向對象,首先理解要它的基礎概念:python

面向對象 ( Object Oriented ) 是將現實問題構建關係,而後抽象成 類 ( class ),給類定義屬性和方法後,再將類實例化成 實例 ( instance ) ,經過訪問實例的屬性和調用方法來進行使用。編程

在不一樣的語言中,對象的定義範圍不一樣。在 Python 中「類」和「類的實例」都稱爲 對象 ( Object ),由於 Python 的類是更頂級的 type 實例化後的對象,也就是常說的「Python 裏萬物皆對象」;而在 Java 等靜態語言中,通常把類的實例稱爲對象。微信

理解了理論知識後,接着經過例子,再理解面向對象的三大特徵:封裝、繼承、多態。dom

下邊咱們把「女媧造人」這個神話故事,用 Python 的面向對象代碼來敘述一遍:學習

假設咱們是女媧(程序設計者),咱們忽然有個想法,想造一羣和本身差很少的小人,小人須要有男女兩種性別,外觀和行爲也有一些差別。那首先咱們分析出,無論什麼性別,都應該有四肢,因此咱們先仿照本身的構造,在腦海中構思泥人的樣子(抽象成基類),而後先賦予泥人一些共有的行爲(定義類的實例方法):spa

class Human(object):

    def __init__(self, name):
        # 有個名字,有兩隻手,兩條腿
        self._name = name
        self.hands = 2
        self.legs = 2

    def introduce_self(self):
        # 介紹本身
        print('我是%s' % self._name)

    def work(self):
        # 工做,但尚未定義具體的行爲
        raise NotImplementedError
複製代碼

而後咱們先捏3個泥人(實例化對象),並給他們取了不一樣的名字(初始化實例屬性):設計

>>> a = Human('大強子')
>>> b = Human('二狗子')
>>> c = Human('三愣子')
複製代碼

咱們讓其中一我的介紹本身(調用實例方法):3d

>>> a.introduce_self()
我是大強子
複製代碼

這裏解釋一下 Human 的代碼,雖然設定了每一個人都要工做,但如何工做須要到具體到不一樣類型的人,因此在基類裏咱們並無定義 work 方法的內容,若是強行調用會拋出異常。code

還有一點,上面定義屬性時,咱們把 self._name 前邊加了下劃線,是由於 Python 裏用下劃線來約定這是一個受保護變量(對應 Java 中的 protected ),咱們不但願外界能直接訪問 name 這個屬性,必需要經過對象調用 introduce_self() 這個行爲介紹了本身,別人才能知道他叫什麼名字,這個過程就稱之爲封裝cdn

而後咱們繼續完成想法,須要給泥人增長兩種性別,而且異性之間能結婚,咱們開始在剛纔泥人模型的基礎上(繼承於基類),構思出兩種性別的泥人的區別(設置不一樣的屬性),而後讓他們均可以工做,但工做的內容不同(調用相同的方法出現不一樣結果,是多態性),並決定讓男人能夠娶女人(將這個行爲定義爲男人的方法)。

import random

class Female(Human):

    def __init__(self, name):
        # 調用父類的初始化方法,依然有名字、兩隻手、兩條腿
        super().__init__(name)
        # 頭髮和力量進行隨機取值
        self.hair = random.randint(3, 5)
        self.power = random.randint(1, 3)
        # 是否已婚
        self.married = False

    def work():
        print('%s採摘了一些果子' % self.name)

class Male(Human):

    def __init__(self, name):
        super().__init__(name)
        self.hair = random.randint(0, 2)
        self.power = random.randint(2, 5)
        self.married = False

    def work():
        print('%s出去打獵了一天' % self.name)

    def marry(self, other):
        # 判斷本身或對方是否已結婚,不然拋出異常
        if self.married is True or other.married is True:
            raise ValueError('法律不支持屢次結婚')
        # 判斷對方是不是女性,不然拋出異常
        if isinstance(other, Female):
            self.married = True
            other.married = True
        else:
            raise TypeError('法律不支持同性結婚')
複製代碼

而後咱們就可讓小人活動起來:

>>> a = Male('大強子')
>>> b = Male('二狗子')
>>> c = Female('翠花')
>>> for h in [a, b, c]:
...     # 調用父類的方法
...     h.introduce_self()
我是大強子
我是二狗子
我是翠花
>>> for h in [a, b, c]:
...     # 多態性使相同的方法產生不一樣的結果
...     h.work()
大強子出去打獵了一天
二狗子出去打獵了一天
翠花采摘了一些果子
>>> a.marry(c)
>>> a.married
True
>>> c.married
True
>>> b.marry(c)
ValueError: 法律不支持屢次結婚
>>> b.marry(a)
TypeError: 法律不支持同性結婚
複製代碼

設計到此結束,咱們來複盤一下整個過程。

咱們先是把人的共有特徵抽象成 Human 基類,這個基類並不用於實例化,而是用於讓 FemaleMale 繼承它,並實現不一樣的行爲。這樣咱們就避免把一些共有的行爲重複在多個類裏定義,若是咱們後續想對人類的行爲進行變更,也只須要修改 Human,繼承 Human 的子類會自動得到新行爲,這是 繼承帶來的好處。

咱們把 name 設計爲受保護變量,外界沒法直接訪問這個屬性,讓每一個人的隱私獲得了保障(一些沒必要要的行爲變得可控),這是 封裝 帶來的好處。

同時咱們在 Human 中預留了 work 方法,並在 FemaleMale 都實現了不一樣的效果,而後咱們知道人人都有 work 方法,所以能夠像 introduce_self 同樣,用循環批量調用 work 方法,這是 多態 帶來的好處。

看到這裏你應該有些理解:面向對象是將客觀事物和一些關係,抽象成具體的模型(類),併爲其設計屬性和方法,即 對象 = 屬性(特徵)+ 方法(行爲)

若是是擁有複雜關係的需求,咱們就應該儘量將互相有關聯的行爲抽象成類,好比每個網頁,網頁中每個組件 等等。實際上面向對象幫助咱們在幾萬行代碼的大型項目中,仍然能夠遊刃有餘,正由於如此,才能發展爲目前應用最爲普遍的編程思想。

但也並非說任什麼時候候都要「面向對象」,過分的封裝和抽象,也會形成代碼可讀性的降低,以及運行效率的降低,所以咱們應該在能將事物抽象化的需求中使用面向對象



最後,不論是面向什麼編程,終究仍是要面向人生

歡迎關注微信公衆號:面向人生編程,本號長期分享經驗向文章

回覆【資料】獲取本人精選的學習視頻及代碼

相關文章
相關標籤/搜索