理解物件導向,首先理解要它的基礎概念:
物件導向是將現實問題構建關係,然後抽象成 類 ( class ) ,給類定義屬性和方法後,再將類例項化成 例項 ( instance ) ,通過訪問例項的屬性和呼叫方法來進行使用。
在不同的語言中,物件的定義範圍不同。在 Python 中 類 和 類的例項 都稱為 物件 ( Object ),因為 Python 的類是更頂級的 type 例項化後的物件;而在 Java 等靜態語言中,一般把類的例項稱為物件。
理解了理論知識後,接著通過例子,再理解物件導向的三大特徵:封裝、繼承、多型。
下邊我們把女媧造人的神話故事用物件導向來敘述一遍:
假設我們是女媧(程式設計者),我們突然有個想法,想造一群和自己差不多的小人,小人需要有男女兩種性別,外觀和行為也有一些差異。那首先我們分析出,不管什麼性別,都應該有四肢,所以我們先仿照自己的構造,在腦海中構思泥人的樣子(抽象成基類),然後先賦予泥人一些共有的行為(定義類的例項方法):
class Human(object):
def __init__(self, name='泥人'):
// 有個名字,有兩隻手,兩條腿
self.name = name
self.hands = 2
self.legs = 2
def introduce_self(self):
// 介紹自己
print('我是%s' % self.name)
複製程式碼
然後我們先捏3個泥人,並給他們取了不同的名字:
>>> a = Human('大強子')
>>> b = Human('二狗子')
>>> c = Human('三愣子')
複製程式碼
我們讓其中一個人介紹自己:
>>> a.introduce_self()
我是大強子
複製程式碼
然後我們繼續完成想法,需要給泥人增加兩種性別,並且異性之間能結婚,我們開始在剛才泥人模型的基礎上(繼承於基類),構思出兩種性別的泥人的區別(設定不同的屬性),然後讓他們都可以工作,但工作的內容不一樣(呼叫相同的方法出現不同結果,是多型性),並決定讓男人可以娶女人(將這個行為定義為男人的方法)。
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 instance(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: 法律不支援同性結婚
複製程式碼
看到這裡你應該會發現,物件導向是更接近人類思維模式的程式設計思想,在這種可以具象化的需求中,可以極大簡化其中的邏輯,讓我們關注於設計物件的屬性和方法。
雖然你確實可以通過寫一長串函式來達到同樣的效果,那實際是另一種程式設計思想:程式導向,通過函式實現過程中一系列的功能,最後按順序組合後達成需求。
並不是說 程式導向 弱於 物件導向,而是在不同的需求中要選擇最合適的設計思路,比如在設計順序執行的指令碼中,明顯程式導向的設計思路是更加適合,如果我們還去定義類就有些累贅了。
這也是剛入門常有的疑問,發現物件導向還要定義類,很是麻煩,這實際是因為沒有遇到適合物件導向的需求導致的。
如果是擁有複雜關係的需求,我們就應該儘可能將互相有關聯的行為抽象成類,比如每一個網頁,網頁中每一個元件 等等。實際上物件導向幫助我們在十萬行程式碼的大型專案中,仍然可以遊刃有餘,正因為如此,才能發展為目前應用最為廣泛的程式設計思想。
最後,不管是面向什麼程式設計,終究還是要面向人生
歡迎關注我的微信公眾號:面向人生程式設計
無論什麼樣的程式設計思想,都不該只存留在程式碼之中,更應伴隨於整個人生旅途,這個公眾號不只聊技術,還會聊產品/網際網路/經濟學等廣泛話題,所以也歡迎非程式設計師關注。