物件導向編程(Object-Oriented Programming)(18):繼承的概念與應用物件導向編程

當程式越寫越大,我們會發現僅靠函數與變數已經難以有效管理。這時候,一種更有組織性的方式就顯得特別重要 —— 物件導向編程(Object-Oriented Programming, OOP)

物件導向編程的基礎

物件導向編程的核心是類別(Classes)物件(Objects)

類別是一個藍圖,定義了一個物件的屬性和行為。物件是類別的實例,包含實際的數據。

我們已經在先前的文章中開始使用這些概念。

class Dog:
  sound = "Woof"
  
  def __init__(self, name, age):
    self.name = name    self.age = age
    
  def bark(self):
    print(Dog.sound)

在這個例子中,我們創建了一個Dog類別,它有屬性(name和age)和方法(bark)。這個類別可以用來創建多個狗的實例,每個實例都有自己的名字和年齡。

物件導向編程的四大支柱

繼承 (Inheritance)

允許類別從其他類別獲取屬性和方法

多型 (Polymorphism)

允許對不同類型的物件執行相同的操作

抽象 (Abstraction)

隱藏複雜性,只展示必要的部分

封裝 (Encapsulation)

將數據和方法打包成一個單元,限制外部訪問

這四個支柱是物件導向編程的基礎。掌握這些概念將使您能夠創建更強大、更可維護的程式。

繼承 (Inheritance)

繼承允許我們創建一個新的類別,該類別獲取現有類別的所有屬性和方法。這就像在現實生活中,孩子從父母那裡繼承特徵一樣。

在物件導向編程中,我們可以創建一個父類別(Parent Class)和一個子類別(Child Class):

class Animal:  # 父類別
  def eat(self):
    print("Nom Nom Nom...eating food!")

class Dog(Animal):  # 子類別
  def bark(self):
    print('Woof!')

class Cat(Animal):  # 子類別
  def meow(self):
    print('Meow!')

在這個例子中,Dog和Cat類別都繼承自Animal類別,因此它們都可以使用eat()方法。

A family tree diagram showing parent and child classes in programming

繼承的優勢

代碼重用

繼承允許我們在多個類別之間共享代碼,減少重複。在我們的例子中,eat()方法只需定義一次,就可以被所有動物類別使用。

層次結構

繼承建立了類別之間的層次關係,反映了實體之間的自然關係。例如,所有的狗和貓都是動物,因此它們的類別可以繼承自動物類別。

專一性

子類別可以添加特定於自己的方法和屬性,同時保留父類別的共同特徵。例如,狗可以吠叫,貓可以喵喵叫,但兩者都可以吃東西。

讓我們看一下繼承的實際應用:

fluffy = Dog()
zoomie = Cat()

fluffy.eat() # 輸出: Nom Nom Nom...eating food!
zoomie.eat() # 輸出: Nom Nom Nom...eating food!

方法覆寫 (Method Overriding)

有時,子類別可能需要改變從父類別繼承的方法的行為。這稱為方法覆寫。

class Animal:
  def __init__(self, name):
    self.name = name  
  def make_noise(self):
    print("{} says, Grrrr".format(self.name))

class Cat(Animal):
  def make_noise(self):
    print("{} says, Meow!".format(self.name))

在這個例子中,Cat類別覆寫了make_noise()方法,使其發出”喵喵”聲而不是一般的動物聲音。

當我們創建一個Cat實例並調用make_noise()方法時,它會使用Cat類別中定義的版本,而不是Animal類別中的版本。

使用super()函數

當覆寫方法時,我們有時候仍然想要使用父類別方法的行為。Python提供了super()函數來實現這一點。

class Animal:
  def __init__(self, name, sound="Grrrr"):
    self.name = name    self.sound = sound
  
  def make_noise(self):
    print("{} says, {}".format(self.name, self.sound))

class Cat(Animal):
  def __init__(self, name):
    super().__init__(name, "Meow!")
    
pet_cat = Cat("Rachel")
pet_cat.make_noise()  # 輸出: Rachel says, Meow!

在這個例子中,Cat類別的__init__方法使用super().__init__()調用父類別的初始化方法,同時提供了一個特定的聲音”Meow!”。這樣,我們可以保留父類別的行為,同時添加或修改子類別特定的行為。

多重繼承 (Multiple Inheritance)

Python允許一個類別從多個父類別繼承,這稱為多重繼承。

多重繼承有兩種主要形式:

  1. 多層繼承:類別從其父類別和祖父類別繼承。例如,AngryDog繼承自Dog,而Dog繼承自Animal。
  2. 直接多重繼承:類別直接從兩個或多個類別繼承。例如,Hybrid繼承自Dog和Wolf。

多重繼承可以非常強大,但也需要小心使用,因為它可能導致命名衝突和複雜的行為。在使用super()時,Python會按照類別定義中列出父類別的順序來解析方法調用。

多層繼承的例子

Animal類別

基本動物特性,如名字和打招呼的能力

class Animal:
  def __init__(self, name):
    self.name = name  def say_hi(self):
    print("{} says, Hi!".format(self.name))

Cat類別

繼承自Animal,獲得其所有特性

class Cat(Animal):
  pass  # 不添加新功能

AngryCat類別

繼承自Cat,因此間接繼承自Animal

class Angry_Cat(Cat):
  pass  # 不添加新功能

使用多層繼承:

my_pet = Angry_Cat("Mr. Cranky")
my_pet.say_hi() # 輸出: Mr. Cranky says, Hi!

直接多重繼承的例子

直接多重繼承允許一個類別從兩個或多個類別直接繼承:

class Animal:
  def __init__(self, name):
    self.name = name
class Dog(Animal):
  def action(self):
    print("{} wags tail. Awwww".format(self.name))

class Wolf(Animal):
  def action(self):
    print("{} bites. OUCH!".format(self.name))
class Hybrid(Dog, Wolf):
  def action(self):
    super().action()  # 調用第一個父類別的方法
    Wolf.action(self)  # 明確調用Wolf的方法
    
my_pet = Hybrid("Fluffy")
my_pet.action()
# 輸出:
# Fluffy wags tail. Awwww
# Fluffy bites. OUCH!

注意:在調用Wolf.action(self)時,我們需要明確傳遞self參數,以確保方法接收到正確的實例。

在多重繼承中,super().action()調用的是Hybrid類別定義中列出的第一個父類別(Dog)的action()方法。如果要調用其他父類別的方法,需要明確指定類別名稱。

結語

繼承 (Inheritance) 是OOP當中最常做使用的。接下來將進一步探討 OOP 的 多型 (Polymorphism)、抽象 (Abstraction) 和封裝 (Encapsulation),幫助你完整掌握 OOP 的四大支柱,進而寫出更具彈性與可維護性的程式。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

返回頂端