---
# System prepended metadata

title: lab08：物件導向程式開發
tags: [計算機概論]

---

- YT物件導向教學：
    - https://www.youtube.com/watch?v=WBrX9n0SWG8
    - https://www.youtube.com/watch?v=fELYoevwnag&t=273s
    - [IThome文章](https://ithelp.ithome.com.tw/articles/10265795)
- 物件導向程式設計（Object-Oriented Programming, OOP）是一種程式設計範式，它將程式組織成物件，這些物件包含資料（屬性）和操作資料的行為（方法）。OOP 使得程式更具結構性、可讀性和可維護性。

```python=
class Robot:
    # 初始化class(self, 其他自己接)
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    # 使用class自己的參數
    def walk(self):
        print(f"{self.name} is walking.")

    # 除了class裡面的參數，還有額外參數
    def sleep(self, hours):
        print(f"{self.name} is going to sleep for {hours} hours.")

# 訪問屬性和方法
my_robot = Robot("助教",23)
print(type(my_robot)) # <class '__main__.Robot'>



print(my_robot.name) # 助教
print(my_robot.age) # 23
my_robot.walk() # 助教 is walking.
my_robot.sleep(15) # 助教 is going to sleep for 15 hours.
```

## oop class attribute（屬性）
- 屬性就想成，是HP、MP這種自身的參數
- 這邊要介紹另一部動漫<<[怪獸8號](https://www.youtube.com/watch?v=CarsLstLs2s)>>，對他很好看ww
![upgit_20240813_1723542553.png](https://raw.githubusercontent.com/kcwc1029/obsidian-upgit-image/main/2024/08/upgit_20240813_1723542553.png)
- 那它裡面要的平凡人，如果要打怪獸，就要穿上解放衣，並且激發解放力
![upgit_20240813_1723542605.png](https://raw.githubusercontent.com/kcwc1029/obsidian-upgit-image/main/2024/08/upgit_20240813_1723542605.png)


### 第一種寫法：每個對象都有自己的屬性
- 在這種寫法中，每個對象都有自己的 `name`、`age` 和 `ingredient` 屬性。


```python
class Robot1:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self.ingredient = "metal"
```

### 第二種寫法：使用類屬性
- 在這種寫法中，屬性 `ingredient` 被定義為類屬性，這意味著所有對象共享同一份 `ingredient` 屬性，而不是每個對象都有自己的副本。
- 這種寫法節省了空間，但如果需要為不同的對象設置不同的屬性值，就不適用。
```python
class Robot:
    ingredient = "metal"
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def greet(self):
        print(f"hi, my name is {self.name}. and i am made of {Robot.ingredient}.")
        
# 創建class
robot1 = Robot("weiwei", 25)
robot2 = Robot("robot2", 30)
robot1.greet()

# 訪問class
print("Robot1 ingredient:", robot1.ingredient)  # 输出 "metal"
print("Robot2 ingredient:", robot2.ingredient)  # 输出 "metal"

# 也可以通过class本身来訪問屬性
print("Class attribute ingredient:", Robot.ingredient)  # 输出 "metal"
```

### 第三種寫法：使用 `self.__class__.attribute`

- 這種寫法類似於第二種寫法，但是在方法中使用了 `self.__class__.ingredient` 來訪問類屬性。這樣做的好處是，如果後續需要修改類屬性的值，只需在類定義中修改一次即可，所有對象都會自動更新，而無需修改每個對象的屬性值。
```python
class Robot:
    ingredient = "metal"
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def greet(self):
        print(f"hi, my name is {self.name}. and i am made of {self.__class__.ingredient}.")


# 創建class
robot1 = Robot("weiwei", 25)
robot2 = Robot("robot2", 30)
robot1.greet()

# 访问class
print("Robot1 ingredient:", robot1.ingredient)  # 输出 "metal"
print("Robot2 ingredient:", robot2.ingredient)  # 输出 "metal"
```



## 建構子與解構子
```python
class Person:
    # 建構子
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def introduce(self):
        print(f"Hi, my name is {self.name} and I am {self.age} years old")

person = Person("助教", 23)
person.introduce()  # Hi, my name is 助教 and I am 23 years old
```
- 解構子是 `__del__` 方法，用於在物件被銷毀前執行清理操作。
```python
# 解構子
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __del__(self):
        print(f"{self.name} is being deleted")

person = Person("助教", 23)
del person  # 助教 is being deleted
```


## static method & class method

### Instance Method
-   第一個參數為 self。
-   實例化後，可以訪問物件屬性和實例方法。

```python
class MyClass:
    def instance_method(self):
        print("This is an instance method.")

obj = MyClass()
obj.instance_method() # This is an instance method.
```

### Class Method 類別方法
-   使用 @classmethod 裝飾器定義的方法，第一個參數為 cls。
-   整個類別相關的操作，可以訪問類別的屬性和其他類別方法。
```python
class MyClass:
    class_variable = "Class Variable"
    @classmethod
    def class_method(cls):
        print(f"Class Method. Class Variable: {cls.class_variable}")

# 使用類別方法
MyClass.class_method() # Class Method. Class Variable: Class Variable
```

### Static Method 靜態方法
-   使用 @staticmethod 裝飾器定義的方法，不需要特定的第一個參數。
-   與類別和實例無關的操作，不訪問實例和類別的屬性。
```python
class MyClass:
    class_variable = "Class Variable"
    @staticmethod
    def static_method():
        print("Static Method.")

# 使用靜態方法
MyClass.static_method() # Static Method.
```

### 綜合示範
```python
class Circle:
    pi = 3.14159
    all_circles = []
    # 建構子
    def __init__(self,radius):
        self.radius = radius
        self.all_circles.append(self)
    
	# Instance Method(最一般的)
    def area(self):
        return self.pi * (self.radius**2)
        
	# Class Method 類別方法
    @classmethod
    def total_area2(cls):
        total = 0
        for i in cls.all_circles:
            total += i.area()
        return total
    
	# Static Method 靜態方法
    @staticmethod
    def total_area():
        total = 0
        for i in Circle.all_circles:
            total += i.area()
        return total

c1 = Circle(10)
print(c1.all_circles) # [<__main__.Circle object at 0x00000102F199B490>]
c2 = Circle(15)
print(c1.all_circles) # [<__main__.Circle object at 0x00000102F19797D0>, <__main__.Circle object at 0x00000102F0B6E490>]
print(c1.area()) # 314.159
print(c1.total_area2()) # 1021.01675
print(c1.total_area()) # 1021.01675
```



## 繼承（inheritance）
- 繼承允許一個類（子類）繼承另一個類（父類）的屬性和方法。
```python
class People:
    def __init__(self, name, age) -> None:
        self.name = name
        self.age = age
    def sleep(self):
        print(f"{self.name} is sleeping...")
    def eat(self):
        print(f"{self.name} is eating...")


class Student(People):
    def __init__(self, name, age, student_id) -> None:
        super().__init__(name, age) # 繼承
        self.student_id = student_id

    def eat(self,food): # 方法可以被覆寫
        print(f"{self.name} is eating now {food}...")

student1 = Student("助教", 23, 10911221)
print(student1.age, student1.student_id) # 23 10911221
student1.sleep() # 助教 is sleeping...
student1.eat("怪獸8號蟲蟲") # 助教 is eating now 怪獸8號蟲蟲...
```

## 多型（Polymorphism）
- 多型允許同一方法在不同物件中有不同的實現。
- 繼承時會覆寫方法
```python
class People:
    def speak(self):
        return "say something"  
class 卡夫卡(People):
    def speak(self):
        return "我還可以以你的身邊為目標前進嗎?"
class 米娜(People):
    def speak(self):
        return "恩，我會一直等你的"
    
people1 = 卡夫卡()
people2 = 米娜()
print(people1.speak()) # '我還可以以你的身邊為目標前進嗎?'
print(people2.speak()) # '恩，我會一直等你的'
```

```python
class 亞白米娜(): # 防衛隊第3部隊的隊長
    def __init__(self):
        self.power = 96
        self.years = 27
        

class 四之宮琪歌露(亞白米娜):
    def __init__(self):
        super().__init__()   # 使用 super() 繼承 亞白米娜 __init__ 裡所有屬性
        self.power = 55 # 如果屬性相同，則覆寫屬性
        self.years = 16
        self.sex = "female"
        

class 日比野卡夫卡(亞白米娜):
    def __init__(self):
        super().__init__()   # 使用 super() 繼承 亞白米娜 __init__ 裡所有屬性
        self.power = 1 # 如果屬性相同，則覆寫屬性
        self.years = 32
        self.sex = "male"

person = 四之宮琪歌露()
print(person.power) # 55
```

## 多重繼承
- 繼承不僅能進行單一繼承，也可以進行多重繼承，例如可以從爸爸身上繼承基因，同時也可以從媽媽身上繼承基因一般
```python
class father():          
    def __init__(self):  
        self.eye = 2
        self.ear = 2
        self.nose = 1
        self.mouth = 1

class mother():          # mother 类
    def language(self):  # mother 的方法
        print('english')
    def skill(self):
        print('painting')

class son(father, mother):    # 继承 father 和 mother
    def __init__(self):      
        super().__init__()    # 繼承爸爸媽媽
    def play(self):           
        print('play phone')

person = son()
print(person.eye)        # 输出 2
person.skill()           # 输出 painting
person.play()            # 输出 ball
```

## 多層繼承
```python
class grandpa():
    def __init__(self):
        self.eye = 2
        self.ear = 2
        self.nose = 1
        self.mouth = 1

class father(grandpa):
    def __init__(self):
        super().__init__()  # 调用父类的构造函数
    def language(self):
        print('english')
    def skill(self):
        print('painting')

class son(father):
    def __init__(self):
        super().__init__()  # 调用父类的构造函数
    def play(self):
        print('ball')

person = son()
print(person.eye)    # 输出 2
person.skill()       # 输出 painting
person.play()        # 输出 ball
```


## 抽象（Abstraction）
- 抽象是指僅顯示物件的必要屬性和行為，隱藏內部的實現細節。
- python要借助套件實現

```python
from abc import ABC, abstractmethod

class Moster(ABC):
    @abstractmethod
    def say(self):
    	return "我會一直等你的"
class 卡夫卡(Moster):
    def say(self):
        return "我還可以以你的身邊為目標前進嗎?"
class 米娜(Moster):
    def say(self):
        return "恩，我會一直等你的"
    
person1 = 卡夫卡() 
person2 = 米娜() 
print(person1.say())# 我還可以以你的身邊為目標前進嗎?
print(person2.say())# 恩，我會一直等你的

# error
thief = Moster()
thief.say() # Can't instantiate abstract class Moster with abstract method say
```

## 封裝（Encapsulation）與私有化
- 封裝是將資料和方法綁定在一起，並隱藏物件的內部細節。可以透過在屬性或方法前加上雙下劃線（__）將其設為私有。

### getter & setter

```python
class Robot:
    def __init__(self,name, age) -> None:
        self.name = name
        self.age = age 
        self.sex = "male" # public
my_robot = Robot("TA", 23)
my_robot.sex = "female" # 數值被隨意篡改了，也正因此有了private的概念
print(my_robot.sex) # female
```

```python
# 增加getter跟setter的概念
class Robot:
    def __init__(self,name, age) -> None:
        self.name = name
        self.age = age 
        self.__sex = "male" 
    # getter
    def getter(self):
        return self.__sex
    # setter
    def setter(self, new_sex): # 更改要透過函數
        self.__sex = new_sex
    
my_robot = Robot("TA", 23)
my_robot.getter() # male
my_robot.setter("female")
my_robot.getter() # female
```

## 裝飾器@property decorator(只讀)

- 如果在類別裡有些屬性不希望被外部更動，就能夠使用 @property 的裝飾器，將該屬性設為唯讀屬性
- 要使用的話，要用屬性的方式歐

```python
class 卡夫卡():
    def __init__(self):
        self.sentence = "我還可以以你的身邊為目標前進嗎?"
    def say(self):
        return self.sentence
    
person1 = 卡夫卡()
person1.say() # '我還可以以你的身邊為目標前進嗎?'

person1.sentence = "我是金句破壞王" # 屬性被更改掉了
person1.say() # '我是金句破壞王'
```

```python
# 將sentence設為only read
class 米娜():
    def __init__(self):
        self.sentence = "恩，我會一直等你的"
    @property
    def say(self):
        return self.sentence

person1 = 米娜()

person1.say # '恩，我會一直等你的'
# person1.say = "4546" # error
```


## Lab08/作業題目
- 繳交方式 : 請到[https://140.116.179.59:8080](https://140.116.179.59:8080)完成作業題目，並將程式碼加上註解(你的理解)，很重要，否則助教有權利扣你分數。
- 禁止抄襲，否則助教會來查水表。






