# 物件導向 #
## 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後才可以使用