物件導向
請問物件導向程式語言有哪些特點,能簡單說明給我聽嗎?
物件導向程式語言 (Object-Oriented Programming
,OOP) 的特點有:
- 物件導向:OOP 程式語言是以物件 (Object) 為基礎建構程式,物件具有狀態 (state) 和行為 (behavior)。
- 繼承 (Inheritance):OOP 程式語言允許一個類別 (class) 從另一個類別繼承屬性和行為。
- 多型 (Polymorphism):OOP 程式語言允許物件在不同的情況下具有不同的行為。
- 封裝 (Encapsulation):OOP 程式語言允許將物件的狀態和行為封裝在一起,保護物件內部狀態不被外界直接存取。
- 抽象 (Abstraction) ,OOP 程式語言將物件的實作細節與使用者分開,使用者只需要知道物件的公開介面而無需知道其實作。
請問物件具有狀態 (state) 和行為 (behavior)。這句話是什麼意思?能用 python 舉例嗎?
物件具有狀態 (state) 和行為 (behavior) 意思是物件具有兩種不同的特性,狀態代表物件的屬性,行為代表物件的方法。
舉例來說,若我們有一個類別叫做 Car
,那麼這個類別可能有一些狀態屬性如 “color”、“speed”、“brand”,而行為可能有 “drive”、“brake”、“turn” 等方法。
用 python 程式碼來實現這個類別可能長得像下面這樣:
|
|
上面這個例子中,類別 Car
有三個狀態屬性 color、speed、brand 以及三個行為方法 drive()、brake()、turn()。
透過創建一個實體物件 my_car = Car("red", 0, "Tesla")
來使用這些方法及屬性。
請問你能用上面的 Car class 寫一個繼承的範例給我看嗎?
當然可以,我們可以創建一個新的類別來繼承 Car 類別,讓新類別繼承 Car 類別的屬性和方法。
例如我們可以創建一個新的類別 ElectricCar
繼承 Car 類別,並且在 ElectricCar 類別中加入新的屬性和方法。
|
|
在這個例子中,ElectricCar
類別繼承了 Car
類別的所有屬性和方法,並且定義了新的屬性 battery_size
和方法 charge()
。
透過使用 super()
函式可以繼承 Car 類別的 init
方法。
使用 my_electric_car = ElectricCar("blue", 0, "Tesla", 100)
來創建實體物件,可以使用 ElectricCar 類別的新屬性及方法。
請問你能用上面的程式碼繼續舉例多型的用法給我看嗎?
當然可以,多型 (Polymorphism)
是指物件在不同的情況下具有不同的行續。 一般來說我們可以使用繼承的類別來實現多型。
以上面程式碼為例,我們可以用 ElectricCar
類別繼承 Car
類別,並重新實現 drive
方法來實現多型的用法。
|
|
在這個例子中,我們在 ElectricCar 和 GasCar 類別中都重新實現了 drive
方法,並且在 drive_car
函數中只接受 Car
的類別,可以看到在 drive_car
函數中傳入不同類別的實體物件會執行不同的 drive 行為
。
這就是多型的用法,可以讓同一個函數或方法支援多種類別的物件,而不需要為每一種類別都寫一個不同的函數或方法。這樣可以增加程式碼的彈性和可讀性。
我們可以在設計類別時統一實現某些方法,並讓類別可以自行選擇如何實現該方法,這樣就可以讓程式碼更具彈性和靈活性。
請問你能用上面的程式碼繼續舉例封裝的用法給我看嗎?
當然可以,封裝 (Encapsulation)
是指將物件的狀態和行為封裝在一起,保護物件內部狀態不被外界直接存取。
在 Python 中,我們可以使用 _
或 __
來表示私有變數和方法
,這樣的變數和方法只能在類別內部存取。
例如,我們可以把 ElectricCar
類別中的 battery_size
屬性改成私有變數:
|
|
在這個例子中,ElectricCar
類別的 battery_size
屬性被定義為私有變數
,只能在類別內部存取。如果外部直接存取該變數的話會產生錯誤。
而我們可以使用私有變數所對應的公有方法 get_battery_size()
來存取私有變數。這樣可以保護類別內部狀態不被外部直接存取,也可以通過公有方法給外部提供適當的存取權限。
你說在 Python 中,我們可以使用 _ 或 __ 來表示私有變數和方法,請問 _ 跟 __ 差在哪裡?
用一個底線 _
表示私有變數和方法並不會真正的阻止外部存取,只是約定俗成的寫法。
而使用兩個底線 __
來表示私有變數和方法會真正的封裝,阻止外部存取,並且子類別也無法存取,更能保證封裝性。
請問你能用上面的程式碼繼續舉例抽象的用法給我看嗎?
可以,以下是之前提到的 Car、ElectricCar、GasCar 程式碼使用抽象類別和抽象方法的寫法:
|
|
在這個範例中,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)
,並且可以互相之間進行溝通和互動。透過物件導向程式設計,可以更加形象地模擬實際世界中的事物,並且更加容易維護和擴展程式碼。