# 物件導向 ### 請問物件導向程式語言有哪些特點,能簡單說明給我聽嗎? 物件導向程式語言 (Object-Oriented Programming, OOP) 的特點有: 1. 物件導向:OOP 程式語言是以物件 (Object) 為基礎建構程式,物件具有狀態 (state) 和行為 (behavior)。 2. 繼承 (Inheritance):OOP 程式語言允許一個類別 (class) 從另一個類別繼承屬性和行為。 3. 多型 (Polymorphism):OOP 程式語言允許物件在不同的情況下具有不同的行為。 4. 封裝 (Encapsulation):OOP 程式語言允許將物件的狀態和行為封裝在一起,保護物件內部狀態不被外界直接存取。 5. 抽象 (Abstraction) ,OOP 程式語言將物件的實作細節與使用者分開,使用者只需要知道物件的公開介面而無需知道其實作。 ### 請問物件具有狀態 (state) 和行為 (behavior)。這句話是什麼意思?能用python舉例嗎? 物件具有狀態 (state) 和行為 (behavior) 意思是物件具有兩種不同的特性,狀態代表物件的屬性,行為代表物件的方法。 舉例來說,若我們有一個類別叫做 "Car",那麼這個類別可能有一些狀態屬性如 "color"、"speed"、"brand",而行為可能有 "drive"、"brake"、"turn" 等方法。 用python 程式碼來實現這個類別可能長得像下面這樣: ```python class Car: def __init__(self, color, speed, brand): self.color = color self.speed = speed self.brand = brand def drive(self): self.speed += 10 def brake(self): self.speed -= 10 def turn(self, direction): print(f"The car is turning {direction}") my_car = Car("red", 0, "Tesla") my_car.drive() my_car.turn("left") print(my_car.speed) # 10 ``` 上面這個例子中,類別 Car 有三個狀態屬性 color, speed, brand 以及三個行為方法 drive(), brake(), turn()。 透過創建一個實體物件 my_car = Car("red", 0, "Tesla") 來使用這些方法及屬性。 ### 請問你能用上面的Car class寫一個繼承的範例給我看嗎? 當然可以,我們可以創建一個新的類別來繼承 Car 類別,讓新類別繼承 Car 類別的屬性和方法。 例如我們可以創建一個新的類別 "ElectricCar" 繼承 Car 類別,並且在 ElectricCar 類別中加入新的屬性和方法。 ```python class ElectricCar(Car): def __init__(self, color, speed, brand, battery_size): super().__init__(color, speed, brand) self.battery_size = battery_size def charge(self): print("The electric car is charging...") def drive(self): if self.battery_size > 0: self.speed += 20 self.battery_size -= 10 else: print("The battery is empty, please charge the car.") my_electric_car = ElectricCar("blue", 0, "Tesla", 100) my_electric_car.drive() my_electric_car.drive() my_electric_car.drive() print(my_electric_car.speed) # 60 print(my_electric_car.battery_size) # 70 ``` 在這個例子中, ElectricCar 類別繼承了 Car 類別的所有屬性和方法,並且定義了新的屬性 battery_size 和方法 charge()。 透過使用 super() 函式可以繼承 Car類別的 init 方法。 使用 my_electric_car = ElectricCar("blue", 0, "Tesla", 100) 來創建實體物件,可以使用 ElectricCar 類別的新屬性及方法。 ### 請問你能用上面的程式碼繼續舉例多型的用法給我看嗎? 當然可以,多型 (Polymorphism) 是指物件在不同的情況下具有不同的行續。 一般來說我們可以使用繼承的類別來實現多型。 以上面程式碼為例,我們可以用 ElectricCar 類別繼承 Car 類別,並重新實現 drive 方法來實現多型的用法。 ```python class ElectricCar(Car): def __init__(self, color, speed, brand, battery_size): super().__init__(color, speed, brand) self.battery_size = battery_size def charge(self): print("The electric car is charging...") def drive(self): if self.battery_size > 0: self.speed += 20 self.battery_size -= 10 else: print("The battery is empty, please charge the car.") class GasCar(Car): def __init__(self, color, speed, brand, gas_level): super().__init__(color, speed, brand) self.gas_level = gas_level def fill_gas(self): self.gas_level = 100 def drive(self): if self.gas_level > 0: self.speed += 15 self.gas_level -= 10 else: print("The gas is empty, please fill the gas.") my_electric_car = ElectricCar("blue", 0, "Tesla", 100) my_gas_car = GasCar("black", 0, "Ford", 60) def drive_car(car): car.drive() drive_car(my_electric_car) drive_car(my_gas_car) print(my_electric_car.speed) # 20 print(my_gas_car.speed) # 15 ``` 在這個例子中,我們在 ElectricCar 和 GasCar 類別中都重新實現了 drive 方法,並且在 drive_car 函數中只接受 Car 的類別,可以看到在 drive_car 函數中傳入不同類別的實體物件會執行不同的drive行為。 這就是多型的用法,可以讓同一個函數或方法支援多種類別的物件,而不需要為每一種類別都寫一個不同的函數或方法。這樣可以增加程式碼的彈性和可讀性。 我們可以在設計類別時統一實現某些方法,並讓類別可以自行選擇如何實現該方法,這樣就可以讓程式碼更具彈性和靈活性。 ### 請問你能用上面的程式碼繼續舉例封裝的用法給我看嗎? 當然可以,封裝 (Encapsulation) 是指將物件的狀態和行為封裝在一起,保護物件內部狀態不被外界直接存取。 在 Python 中,我們可以使用 _ 或 __ 來表示私有變數和方法,這樣的變數和方法只能在類別內部存取。 例如,我們可以把 ElectricCar 類別中的 battery_size 屬性改成私有變數: ```python class ElectricCar(Car): def __init__(self, color, speed, brand, battery_size): super().__init__(color, speed, brand) self.__battery_size = battery_size def charge(self): print("The electric car is charging...") def drive(self): if self.__battery_size > 0: self.speed += 20 self.__battery_size -= 10 else: print("The battery is empty, please charge the car.") def get_battery_size(self): return self.__battery_size my_electric_car = ElectricCar("blue", 0, "Tesla", 100) print(my_electric_car.get_battery_size()) #100 ``` 在這個例子中, ElectricCar 類別的 battery_size 屬性被定義為私有變數,只能在類別內部存取。如果外部直接存取該變數的話會產生錯誤。 而我們可以使用私有變數所對應的公有方法 get_battery_size() 來存取私有變數。這樣可以保護類別內部狀態不被外部直接存取,也可以通過公有方法給外部提供適當的存取權限。 ### 你說在 Python 中,我們可以使用 _ 或 __ 來表示私有變數和方法,請問_ 跟__ 差在哪裡? 用一個底線 (_) 表示私有變數和方法並不會真正的阻止外部存取,只是約定俗成的寫法。 而使用兩個底線 (__) 來表示私有變數和方法會真正的封裝,阻止外部存取,並且子類別也無法存取,更能保證封裝性。 ### 請問你能用上面的程式碼繼續舉例抽象的用法給我看嗎? 可以,以下是之前提到的 Car、ElectricCar、GasCar 程式碼使用抽象類別和抽象方法的寫法: ```python from abc import ABC, abstractmethod class Car(ABC): def __init__(self): self.__year_model = 0 self.__make = "" self.__speed = 0 @abstractmethod def drive(self): pass class ElectricCar(Car): def __init__(self): super().__init__() self.__battery_type = "" def set_battery_type(self, battery_type): self.__battery_type = battery_type def get_battery_type(self): return self.__battery_type def drive(self): print("Electric car is driving.") class GasCar(Car): def __init__(self): super().__init__() self.__fuel_type = "" def set_fuel_type(self, fuel_type): self.__fuel_type = fuel_type def get_fuel_type(self): return self.__fuel_type def drive(self): print("Gas car is driving.") #create object car = ElectricCar() car.drive() car = GasCar() car.drive() ``` 在這個範例中,Car類別是一個抽象類別,它定義了一個抽象方法 drive()。 ElectricCar 和 GasCar 類別都繼承自 Car 類別,並實現了 drive() 方法。 這樣的設計可以達到封裝的目的,同時也可以達到多型的目的。 並且因為Car類別是抽象類別,所以不能直接建立Car類別的物件,只能用它的子類別來建立物件。 ### 有了繼承的特點為何還需要抽象?感覺不出這兩者有何差別 繼承的作用是讓子類別可以繼承父類別的屬性和方法,使得子類別可以共用父類別的程式碼,達到代碼重用的目的。這樣可以讓程式碼更簡潔,並且可以讓子類別擁有父類別的特徵。 而抽象則是讓類別有共同的特徵和行為,抽象類別不能被實例化,而是用來被其他類別繼承。抽象類別中可以定義抽象方法(abstract method)和普通方法,抽象方法只有定義,沒有實現。在子類別中必須實現抽象方法。這樣可以確保所有子類別都有相同的行為,但實現可能不同。 在車的例子中,我們可以用繼承的方式,讓ElectricCar和GasCar繼承Car的屬性,例如make, model, year_model。而用抽象的方式,我們可以在父類別Car中定義一個drive方法,並在子類別中實現drive方法,這樣可以確保所有車子都有drive這個行為。 ### 實際業務上來說,何時會想用繼承何時會想用抽象? 實際業務上,繼承和抽象會根據實際需求而使用。 - 繼承: 要繼承另一個類別的特徵和行為時,就可以使用繼承。例如,你有一個車類別,並且你需要創建一個電動車和汽油車類別,這兩個類別都有許多相同的特徵和行為,那麼你可以使用繼承,將車類別的特徵和行為繼承到電動車和汽油車類別中。 - 抽象 當你有一些類別需要共用同一個介面或行為時,就可以使用抽象。例如,你有一個車類別,並且你需要創建多種不同類型的車,例如電動車、汽油車、柴油車等,這些車都需要有 drive 這個行為,那麼你可以使用抽象類別來定義一個 drive 方法,並在電動車、汽油車、柴油車等類別中實現 drive 方法,這樣就可以確保所有車都有 drive 這個行為。 總結來說,繼承是用來繼承父類別的特徵和行為,而抽象則是用來確保類別具有共同的特徵和行為。 ### 請問你說的特徵具體來說是指什麼東西? 特徵是指類別所具有的屬性和行為,包括資料和函式。 屬性是指類別中的變數,它們用來儲存類別中的資料。例如在之前的例子中,Car類別中的屬性有 make, model, year_model。 而行為是指類別中的函式,它們用來定義類別的動作。例如在之前的例子中,Car類別中的行為有 drive, get_make, get_model等。 這些屬性和行為就是類別的特徵。 ### 請問物件導向為何叫做物件導向? 物件導向程式語言之所以叫做物件導向是因為它重視物件 (Object) 這個概念。在物件導向程式語言中,程式設計師可以使用類別 (Class) 來定義物件的共性,並使用物件來實例化類別。 物件具有狀態 (state) 和行為 (behavior) ,並且可以互相之間進行溝通和互動。透過物件導向程式設計,可以更加形象地模擬實際世界中的事物,並且更加容易維護和擴展程式碼。