# 物件導向 # ## POP VS OOP - **程序導向設計-POP** (procedure-Oriented Programming):把要實現的目標,先拆分成一個一個步驟,再依序完成,適用於簡單、架構不大、整體程式不長的情況。 - **物件導向設計-OOP** (Object-Oriented Programming):更像現實世界,首先考慮每種類型有哪些性質,並用物件賦予實際屬性,先建立出每種物件的屬性、方法,再描述相互之間的作用、關係。又,在方法(method)需要用到class裡面的屬性(attribute)時,不須再另外提供,而是可以從class中直接調取。在程式變多,變複雜時,能使其看起來較為清晰。 ## Class(類) ## class即為物件(object)的設計圖,包含建構子(constructor)、屬性(attribute)及方法(method)。 - 類別(Class):設計圖,ex:貓咪 - 建構子(Constructor):class特有的方法(method),是固定的 - 屬性(Attribute):設計圖的變數,ex:貓咪的顏色變數-->定義橘色 - 方法(Method):設計圖的函數,想像設計圖定義貓咪的某些動作 - 物件(Object):把設計圖具體化,可以使用類(class)中的方法跟屬性 | 類 Class | 屬性 Attribute | 物件 Object | | -------- | -------------- | ----------- | | Fruit | 顏色、大小、重量 | 蘋果、橘子 | | Car | 門、顏色、引擎款式 | Toyota、Honda | #### 格式: ```python= class 類的名稱(要繼承的類): #建構子(固定格式) def __init__(self,物件初始化參數): 程式邏輯 #方法 def 自定義方法(self,自訂義所需參數): 程式邏輯 ``` #### 範例: ```python= class Cat(): # Cat的設計圖,此次範例沒有要繼承的東西 def __init__(self): # 建構子 # 屬性 self.color = 'orange' self.leg = 'long' # 方法 def run(self): print('cat is running') mary = Cat # mary是Cat的具象化物件(object) mary.run() # 使用物件裡面的方法 ``` ### Class的特性 1. 繼承(Inheritance):繼承前面的類(class) - 方法覆寫(Method Overriding):若子類有父類相同的屬性或方法,會覆寫,留下最新的。 - 多層繼承(Multi-Level Inheritance):爸爸繼承爺爺,兒子繼承爸爸,則兒子亦繼承爺爺的屬性或方法,若遇覆寫,則一路覆寫,只留下最新的屬性及方法。 - 多重繼承(Multiple Inheritance):一個類可以繼承多個類,若遇到繼承的類有相同的屬性或方法,以寫在前面的類為主。 - **注意:** 當新的class輸入"__init__()"時,其結構已被重建,若要繼承,則需加入"super().__init__()",或試用希望繼承之類的名字,例如:grand.__init__(),再寫上希望繼承的屬性。另外而方法會被繼承而不被洗白 #### 繼承_範例: ```python = class Grandfather: def __init__(self, height): # 此類別需屬性:height self.height = height #當object透過__init__()建立時,亦建立height這個屬性並等待object給與 def phone(self): print("no cellphone") class Father(Grandfather): def __init__(self, height, weight, work): # 此類別需屬性:height,weight,work super().__init__(height) # 從grandfather繼承屬性height self.weight = weight self.work = work def phone(self): print("using Xiaomi") class Mother: def __init__(self, height, weight, work): self.height = height self.weight = weight self.work = work def phone(self): print("using iphone") def wakeup(self): print("wake up early") class Son(Father, Mother): def __init__(self, height, weight, work): super().__init__(height, weight, work) # 從father和mother繼承屬性height,weight,work pass def phone(self): print("using pixel") # 將類別具體化並給予屬性(參數) grandpa = Grandfather("tall") Max = Father("tall", "heavy", "businessman") Sally = Mother("middle", "middle", "businesswoman") Neil = Son("tall", "heavy", "student") print(Neil.height) print(Neil.weight) print(Neil.work) Neil.phone() Neil.wakeup() # 繼承自mother ``` 2. 封裝(Encapsulation):如果類(class)裡面的屬性或方法只想在類(class)裡面被呼叫,但不想在物件(object)被呼叫,在屬性或方法前面加2個'_'即可-->"__" - 私有屬性(Private Attribute):封裝屬性 - 私有方法(Private Method):封裝方法 #### 封裝_範例: ```python= class Score: def __init__(self, __test1, test2, test3, homework): self.__test1 = __test1 # test1即為封裝屬性 self.test2 = test2 self.test3 = test3 self.homework = homework self.final_score = 0 def __count_final_score(self): # count_final_score即為封裝方法 self.final_score = (self.__test1 + self.test2 + self.test3 + self.homework) / 4 print("final score = ", self.final_score) def pass_or_not(self): if self.final_score > 70: print("pass") else: print("can not pass") neil = Score(85, 75, 60, 90) print(neil.__test1) # 因為是封裝屬性,故結果得到:AttributeError: 'score' object has no attribute '__test1' print(neil.homework) neil.count_final_score() # 因為是封裝方法,故得到結果:AttributeError: 'score' object has no attribute 'count_final_score' neil.pass_or_not() ``` 3. 多型(Polymorphism):不同的類被具體化成為物件後,可以分別作用不互相影響 #### 多型_範例: ```python= class Score: def __init__(self, test1, test2, test3, homework): self.test1 = test1 self.test2 = test2 self.test3 = test3 self.homework = homework self.final_score = 0 def count_final_score(self): self.final_score = (self.test1 + self.test2 + self.test3 + self.homework) / 4 print("final score = ", self.final_score) def pass_or_not(self): if self.final_score > 70: print("pass") else: print("can not pass") neil = Score(50, 80, 62, 45) neil.count_final_score() neil.pass_or_not() joey = Score(85, 75, 60, 90) joey.count_final_score() joey.pass_or_not() ``` score這個class被具現化成neil和joey二種不同的object,但只要各自給定參數,就能獨立運作,不會互相影響 ### self self即為自己本身,可以當作自己跟自己溝通的橋樑,亦可自己呼叫自己,透過以下舉例協助了解self的功用。 #### 沒有self ```python= class Cat(): def __init__(): color = 'orange' legs = 'long' def run(): print('cat is running') Cat.run() ``` 因為沒有self,故亦不需具現化,不用創造object #### 有self ```python= class Cat: def __init__(self, color, legs): self.color = color self.legs = legs def run(self): print(self.color, "cat is running with it's", self.legs, "legs") tony = Cat("orange", "long") tony.run() ``` 加上self後,可以在同一個class中呼叫自己的屬性,但是需用object具現化class後才可以使用