Shape
是個抽象類別,裡頭定義了例如名稱、面積、周長等等方法。而 Rectangle
和 Triangle
則繼承 Shape
並實作上述的方法。因此這裡也同先前講繼承時提到的,Abstract class 和繼承 Abstract class 的 class 有層次上的關係,而通常這麼做的原因是為了實現多型。from abc import ABCMeta, abstractmethod
class Book(object, metaclass=ABCMeta):
def __init__(self, title, author):
self.title = title
self.author = author
@abstractmethod
def display(self): pass
class MyBook(Book):
def __init__(self, title, author, price):
super().__init__(title, author)
self.price = price
def display(self):
print("Title: " + self.title + "\nAuthor: " + self.author + "\nPrice: " + str(self.price))
title = input()
author = input()
price = int(input())
new_novel = MyBook(title, author, price)
new_novel.display()
ABCMeta
來達到這件事情。什麼是 metaclass 呢?我們可以理解為是 class 的 class,因為在 Python,什麼東西都是 object,包含 class 本身也是一個 object,那麼既然是 object,一定會有一個像是 class 的東西來產生這個 object,而這個 class 的 class 就是 metaclass 啦!而一般的 class 預設的 metaclass 是 type
。當我們去宣告了一個 class 例如 A
,而要用 A
去產生 object 的時候,其實是會先 call type
的 __call__
Method,而 __call__
的行為是去 call A
的 __new__
和 __init__
。所以假使我們今天改變了本來預設的 metaclass,就能夠改變物件生成的行為。例如常見會去使用 metaclass 的一種情境是 Singleton object,就是利用自定義 metaclass 來避免每次都去產生一個新的 object,有興趣的可以看看這裡。metaclass=ABCMeta
,就是這裡的 class Book,這是官方的 library 所提供的 (參考)。而抽象的方法必須在其宣告的上面加上 @abstractmethod
這個 decorator (Python 的 decorator 是一種特殊的 function,把 function 當做參數傳入,再傳回 function,而在其中可以為本來的 function 加上更多能力,可以參考這裡),就像這裡的 display
這個 Method 就是抽象的方法,直接用 pass
來略過實作。 class MyBook
則繼承了 Book
並且實作了 display
囉!TypeError
,如果子類別忘記實作所有的抽象方法,那麼該子類別也會被視為 abstract class 而在 instantiate object 時同樣出現 TypeError
囉!abc
的部分可以以參考這裡。import scala.io.StdIn
abstract class Book(val title: String, val author: String) {
def display()
}
class MyBook(override val title: String, override val author: String, val price: Int) extends Book(title, author) {
def display(): Unit = {
println("Title: " + title)
println("Author: " + author)
println("Price: " + price)
}
}
object Solution {
def main(args: Array[String]) {
val (title, author) = (StdIn.readLine(), StdIn.readLine())
val price = StdIn.readInt()
val newBook = new MyBook(title, author, price)
newBook.display()
}
}
abstract class
的關鍵字,abstract class Book
中的 def display()
就是宣告抽象的方法。而 MyBook
在繼承 Book
的方式就跟上一篇講的一樣,就是用 extends
,然後必須實作 display()
這個 Method。假使沒有實作的話,那麼 Book
仍然也還是一個 abstract class
,就必須要加上 abstract
這個關鍵字,不然 compiler 會報錯 class MyBook needs to be abstract, since method display in class Book of type ()Unit is not defined
。今天談的 abstract class 主要還是 OOP 中關於繼承的部分,也就是在於層次上的抽象,並且有效率地去複用程式碼。今天也提到了 abstract class 和 interface 的一些異同,而之後我們會再談更多關於 interface 的大小事,Golang 和 Rust 就不會寂寞啦!