## 概要 - 在學習程式語言時,或多或少都有聽過物件導向程式設計(Object-oriented programming,簡稱OOP),它是一個具有物件(Object)概念的開發方式,能夠提高軟體的重用性、擴充性及維護性,在開發大型的應用程式時更是被廣為使用,所以在現今多數的程式語言都有此種開發方式,Python當然也不例外。而要使用物件導向程式設計就必須對類別(Class)及物件(Object)等有一些基本的了解,包含了: 1. 類別(Class) 2. 物件(Object) 3. 屬性(Attribute) 4. 建構式(Constructor) 5. 方法(Method) ```python=3.8 # 汽車類別 class Cars: # 建構式 def __init__(self, color, seat): self.color = color # 顏色屬性 self.seat = seat # 座位屬性 # 方法(Method) def drive(self): print(f"My car is {self.color} and {self.seat} seats.") ``` ## Class - 什麼是 class - 就是物件(Object)的藍圖(blueprint)。就像要生產一部汽車時,都會有設計圖,藉此可以知道此類汽車會有哪些特性及功能,類別(Class)就類似設計圖,會定義未來產生物件(Object)時所擁有的屬性(Attribute)及方法(Method)。 ```python3= class classname:   statement #範例一 class Cars: #範例二 class MyCars: ``` - 關鍵概念 1. 物件(Object): 類別的實例稱為物件。物件是類別的具體實體,它擁有類別定義的屬性和方法。 - Python也提供了一個函式isinstance()來判斷類別(Class)與物件(Object)的關係 ```python3= # object_name = classname() # isinstance(object_name, class_name) ``` ```python3= # 汽車類別 class Cars: pass # 摩托車類別 class Motorcycle: pass # 建立Cars類別的物件 mazda = Cars() print(isinstance(mazda, Cars)) # 執行結果:True print(isinstance(mazda, Motorcycle)) # 執行結果:False ``` 2. 屬性(Attribute):類別的屬性是物件的特徵或數據成員。它們存儲在物件中並描述物件的狀態。 ```python3= object_name.attribute_name = value ``` ```python3= class Car: pass car = Car() car.color = "blue" car.wheel = 4 print(car.color, car.wheel) # 輸出 blue 4 ``` 3. 建構式(Constructor):於建立物件(Object)的同時,會自動執行的方法(Method)。所以通常我們會在建構式(Constructor)中初始化物件(Object)的屬性值(Attribute)。至少要有一個self參數,之後利用逗號區隔其他屬性 ```python3= # 汽車類別 class Cars: # 建構式 def __init__(self, color, seat): self.color = color # 顏色屬性 self.seat = seat # 座位屬性 mazda = Cars("blue", 4) toyota = Cars("black", 4) ``` 4. 方法(Method):類別的方法是與物件相關聯的函數,它們用於執行特定的操作或操作物件的屬性。 ```python3= # 汽車類別 class Cars: # 建構式 def __init__(self, color, seat): self.color = color # 顏色屬性 self.seat = seat # 座位屬性 # 方法(Method) def drive(self): print(f"My car is {self.color} and has {self.seat} seats.") mazda = Cars("blue", 4) mazda.drive() #執行結果:My car is blue and has 4 seats. ``` ## 物件導向特性 1. 繼承(Inheritance): 繼承是一種概念,它允許你創建一個新的類別,基於現有類別(父類別或基類別)的定義,並且可以繼承父類別的屬性和方法。 - 定義: 繼承是一種機制,允許你創建一個新的類別(子類別)基於現有類別(父類別或基類別)的定義。子類別繼承了父類別的屬性和方法,並且可以擴展或修改它們,同時也可以新增自己的屬性和方法。 - 用途: 繼承提供了代碼重用的能力,可以建立層次結構,使相似的類別共享通用的屬性和方法。它也支援多態性的實現。 - 範例: 如果有一個基類別 動物(Animal),你可以創建多個子類別如 狗(Dog)、貓(Cat),這些子類別可以繼承 動物 的通用行為,同時具有自己特定的行為和屬性。 ```python3= # 定義一個基本的動物類別 class Animal: def __init__(self, name): self.name = name def speak(self): pass # 在基本的動物類別中,speak方法不做任何事情 # 定義子類別,繼承自動物類別 class Dog(Animal): def speak(self): return f"{self.name} 咬了一口!汪汪汪!" # 定義另一個子類別 class Cat(Animal): def speak(self): return f"{self.name} 抓了一只老鼠。喵喵喵!" # 創建動物實例 dog = Dog("小狗") cat = Cat("小貓") # 使用子類別的方法 print(dog.speak()) # 輸出:小狗 咬了一口!汪汪汪! print(cat.speak()) # 輸出:小貓 抓了一只老鼠。喵喵喵! ``` 2. 封裝(Encapsulation): 封裝是指將數據(屬性)和相關的操作(方法)封裝在一個類別中。這意味著類別可以控制其內部數據的訪問權限。 - 定義: 封裝是一種將數據(屬性)和操作(方法)包裝成單個實體的概念,同時限制外部訪問和操作這些內部細節的能力。通過封裝,你可以隱藏物件的內部實現細節,僅提供公開的界面。 - 用途: 封裝提高了程式碼的安全性和可維護性,並支持設計模式,如 getter 和 setter 方法,以控制對屬性的訪問。 - 範例: 一個類別可以將其屬性設置為私有(private),並提供公共的方法來訪問和修改這些屬性。這樣可以確保對屬性的訪問是受控的,並且不會直接訪問和修改內部數據。 ```python3= class Student: def __init__(self, name, age): self.__name = name # 使用雙下劃線開頭的屬性是私有的 self.__age = age # 定義公有方法來訪問私有屬性 def get_name(self): return self.__name def get_age(self): return self.__age # 定義公有方法來設置私有屬性 def set_name(self, name): self.__name = name def set_age(self, age): if age >= 0: self.__age = age else: print("年齡不能為負數") # 創建學生對象 student = Student("小明", 20) # 使用公有方法訪問和設置私有屬性 print("學生姓名:", student.get_name()) # 輸出:學生姓名: 小明 print("學生年齡:", student.get_age()) # 輸出:學生年齡: 20 student.set_name("小紅") student.set_age(-22) # 嘗試設置年齡為負數,會顯示錯誤訊息 ``` 3. 多態(Polymorphism): 多態性是指不同的類別可以對相同的方法名稱進行不同的實現。這使得你可以使用相同的方法名稱調用不同類別的方法,根據實際對象的類型執行不同的操作。 - 定義: 多態性是指不同的類別可以對相同的方法名稱進行不同的實現。這允許你使用相同的方法名稱調用不同類別的方法,根據實際對象的類型執行不同的操作。 - 用途: 多態性提高了程式碼的靈活性和可擴展性。它使得代碼可以針對不同的對象執行相似的操作,無需關心具體的對象類型。 - 範例: 如果有一個 動物 類別和多個子類別,你可以創建一個通用的 發聲(makeSound) 方法,然後不同的子類別可以對這個方法進行不同的實現,如 狗 會 bark,貓 會 meow。 ```python3= class Animal: def speak(self): pass class Dog(Animal): def speak(self): return "汪汪汪!" class Cat(Animal): def speak(self): return "喵喵喵!" class Bird(Animal): def speak(self): return "嘰嘰喳喳!" # 創建不同的動物對象 dog = Dog() cat = Cat() bird = Bird() # 呼叫相同的方法,但它們根據具體的類別而有不同的實現 print(dog.speak()) # 輸出:汪汪汪! print(cat.speak()) # 輸出:喵喵喵! print(bird.speak()) # 輸出:嘰嘰喳喳! ``` - 多型性(Polymorphism)是物件導向程式設計的一個重要概念,它允許不同的類別共享相同的介面,但可以有不同的實現方式。Python 中的多型性通常通過方法重寫(Method Overriding)實現。 ```c++= #include <iostream> using namespace std; // 基類別 class Animal { public: virtual void speak() { cout << "這是動物的聲音" << endl; } }; // 子類別 1 class Dog : public Animal { public: void speak() override { cout << "汪汪汪!" << endl; } }; // 子類別 2 class Cat : public Animal { public: void speak() override { cout << "喵喵喵!" << endl; } }; int main() { // 創建不同的動物對象 Animal* animal1 = new Animal(); Animal* animal2 = new Dog(); Animal* animal3 = new Cat(); // 調用speak方法 animal1->speak(); // 輸出:這是動物的聲音 animal2->speak(); // 輸出:汪汪汪! animal3->speak(); // 輸出:喵喵喵! delete animal1; delete animal2; delete animal3; return 0; } ``` ## 不同屬性 1. 實體屬性(Instance Attribute) - 實體屬性是與類別的特定實體(即對象)相關聯的屬性。 - 每個類別的不同實體可以擁有不同的實體屬性值。 - 通常,實體屬性是在建立類別的實例時賦予的,並且每個實例都可以有自己的值。 - 實體屬性可以在方法中訪問和修改。 ```python3= class Dog: def __init__(self, name, age): self.name = name # 實體屬性 name self.age = age # 實體屬性 age # 建立兩個不同的實例 dog1 = Dog("Buddy", 3) dog1.color = "brown" dog2 = Dog("Molly", 5) # 每個實例都有自己的實體屬性值 print(dog1.name) # 輸出: "Buddy" print(dog2.age) # 輸出: 5 ``` 2. 類別屬性(Class Attribute) - 類別屬性是與整個類別相關聯的屬性,而不是特定的實例。 - 所有該類別的實例共享相同的類別屬性值。 - 通常,在類別的定義中直接分配給屬性,而不是在實例的初始化方法中賦予的。 - 類別屬性可以透過類別本身或實例來訪問。 ```python3= class Circle: pi = 3.14159265 # 類別屬性 pi def __init__(self, radius): self.radius = radius def area(self): return Circle.pi * self.radius * self.radius # 建立兩個不同的實例 circle1 = Circle(5) circle2 = Circle(7) # 使用類別屬性 pi print(Circle.pi) # 輸出: 3.14159265 # 也可以使用實例訪問類別屬性 print(circle1.pi) # 輸出: 3.14159265 # 類別屬性在所有實例之間共享 print(circle2.area()) # 輸出: 153.938040375 ``` ## Method 類別 1. 實體方法(Instance Method) - 實體方法是定義在類別中,並且操作類別的實例的方法。 - 它們的第一個參數通常是 self,代表實例本身,並且可以訪問和修改該實例的實體屬性。 - 實體方法可以訪問實體的狀態,並且可以修改這些狀態。 ```python3= class Dog: def __init__(self, name, age): self.name = name self.age = age def bark(self): print(f"{self.name} says woof!") # 創建一個 Dog 實例 my_dog = Dog("Buddy", 3) # 呼叫實體方法 bark my_dog.bark() # 輸出: "Buddy says woof!" ``` 2. 類別方法(Class Method) - 類別方法是與類別本身相關聯的方法,而不是實例。 - 它們使用 @classmethod 裝飾器來定義,並將第一個參數設定為 cls,代表類別本身。 - 類別方法可以訪問和修改類別屬性,但不能訪問實例屬性。 ```python3= class Circle: pi = 3.14159265 # 類別屬性 @classmethod def set_pi(cls, new_pi): cls.pi = new_pi # 使用類別方法修改類別屬性 Circle.set_pi(3.14) # 訪問修改後的類別屬性 print(Circle.pi) # 輸出: 3.14 ``` 3. 靜態方法(Static Method) - 靜態方法是與類別相關聯的方法,但它們不訪問類別或實例的狀態。 - 靜態方法使用 @staticmethod 裝飾器來定義,並不需要特定的第一個參數。 - 靜態方法通常用於將某些功能包裝在類別中,但這些功能不需要訪問類別或實例的屬性。 ```python3= class MathUtils: @staticmethod def add(x, y): return x + y # 呼叫靜態方法 result = MathUtils.add(5, 3) print(result) # 輸出: 8= ``` ## Class Diagram - 軟體工程和物件導向程式設計中,可以使用類別圖(Class Diagram)來規劃一個物件的屬性和方法。類別圖是統一建模語言(UML)的一部分,用於描述類別(Class)、物件(Object)、屬性(Attribute)和方法(Method)之間的關係和結構 ![](https://hackmd.io/_uploads/S1yIkw2ya.png) ### 常見的元素 1. 類別(Class): 類別是一個用於描述物件的模板,它包括屬性和方法。一個類別代表一個實體或一個概念。 2. 屬性(Attribute): 屬性是描述物件狀態的特徵或數據成員。在類別圖中,你可以使用類別的名稱和分隔線表示屬性。例如,如果你有一個叫做 "Person" 的類別,它可以有屬性如 "name"、"age"、"address" 等。 3. 方法(Method): 方法是描述物件行為的操作或函數。在類別圖中,你可以使用類別的名稱,後跟一個小括號和方法名稱表示方法。例如,如果你有一個 "Person" 類別,它可以有方法如 "getAge()"、"setName()" 等。 - 類別(Class)中的方法(Method)通常會在方法名稱後面接著一個數據類型(Data Type)的返回值,以指定該方法的返回值類型。這是為了確定方法執行後會返回什麼樣的數據。 - 以下是一些主要的原因: 1. 類型安全性: 指定方法的返回值類型可以提供編譯器或開發環境更多的信息,以確保程式碼的類型安全性。如果某個方法聲明返回整數,那麼編譯器可以在編譯時期檢查是否將整數返回給調用該方法的地方。這有助於減少類型相關的錯誤。 2. 程式碼理解和維護: 指定方法的返回值類型可以讓其他開發者更容易理解程式碼,並確定如何使用該方法的返回值。這有助於提高程式碼的可讀性和可維護性。 3. 自文檔化: 返回值類型的註釋有助於自動文檔生成工具生成有關方法的文檔。這使得開發者可以輕鬆查閱有關方法如何使用的信息。 4. 方法連鎖調用: 在某些程式語言中,方法的返回值類型可以影響方法連鎖調用的可行性。例如,如果一個方法返回了一個特定的對象類型,則可以繼續調用該對象的方法,形成一個連鎖。 4. 可見性 (Visibility):各屬性與方法前面都會有個符號,在類別圖中我們稱之為Visibility,總共有:「+#-」,依序為「public」、「protected」、「private」 - Public(公開): 公開的成員可以在類別的任何地方訪問,以及在類別的外部訪問。通常,這些成員被設計為可以公開訪問的,用於提供對外部使用者的介面。在許多程式語言中,公開成員通常使用關鍵字如 public 或者是不使用特定關鍵字來標識。 - Private(私有): 私有的成員只能在類別的內部訪問,無法從類別的外部訪問。這可以提供封裝性,防止外部程式碼直接存取和修改類別的內部狀態。在許多程式語言中,私有成員通常使用關鍵字如 private 來標識。 - Protected(保護): 保護的成員可以在類別的內部訪問,以及在衍生(子)類別中訪問。這種可見性通常用於實現繼承和衍生類別之間的訪問控制。在一些程式語言中,保護成員使用關鍵字如 protected 來標識。 ![](https://hackmd.io/_uploads/B1J1-v2ya.png =200x)