---
# System prepended metadata

title: 物件導向
tags: [python]

---

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