第一次看這隻小老鼠
在 java 裡面常常會看見下面這樣的用法
@Override
void method() {
}
上面有個小老鼠的 @Override
便是 annotation 。
這個 @Override 的作用是開發者繼承某個 class 之後,想要覆寫父類別的時候加上這個 annotation 可以讓編譯器知道你想覆寫,因此編譯器會檢查父類別是否有相同的 method ,以免你原本想要覆寫父類別的 method 結果卻手殘打錯字沒有真的覆寫到而發生意外。
因此 annotation 的作用就是讓被 annotation 標籤上的 class, method 之類的東西額外的增加資訊。
再看小老鼠
一開始我也不知道這 annotation 到底有什麼用途,直到我看見 python 的幾個 web 框架有以下的做法
@get('/index')
def getIndex():
return "<p> hello </p>"
這是個小小的 route ,說明的是如果使用者使用 GET 方法連線到 /index 這個網址,就使用被標籤的 method ,而這個被標籤的 method 會回傳一串 html 作為回應,這裡不必太過在意後面的行為。
小老鼠進化史
從前面看來,發現似乎如此一來前面的 getIndex() 邏輯是很清晰的,而不會混雑著太長的設定路徑以及 http method 的邏輯,而是交由背景某個東西去運作,只需要使用 @get('/index')
這樣的標籤,就能讓背景的魔手去設定。
而這樣的概念爬了一下歷史,可以發現似乎是在 C 時代就會想使用 macro 去改變 function 的宣告,像是在 php 可以常常看到像是下面這樣的方法去宣告 function
// hello.c
PHP_FUNCTION (hello) {
// do something
}
而當中的 PHP_FUNCTION 是個 macro 會去將這整個文字內容改成符合自己要求的 function 結構,隨便瞎掰一個可能的例子,例如:
// hello.c
php_function_ret *hello (int a, int b) {
// do something
}
這樣可以將這段可重用的邏輯抽離出來並且隱藏又臭又長的 code ,而且如此一來還有一點點這是給 hello 這個 function 進行撰寫程式內的設定檔的概念
因此可以稍微整理出我們對此類的需求大概如下:
- meta:想將使用者的程式進行設定,或者標記上某些屬性
- 改變流程: 執行使用者的內容前後,想添加某些程式去執行
回頭看看 java annotation
因此針對第一點,java 提出了 annotation 的概念,但是僅能加上屬性不能改變被標記程式的流程。
所以當初 java 這點被廣泛的應用拿來生成文件以及生成設定檔。
不過在這個流程反轉的年代, java annotation 並沒有因為只能作為 meta 而失去威力。
只要是有套上框架的程式,流程一開始都是交由框架去跑,所以套上框架的程式只要在編譯或是建置的時候,掃描所有 code 裡有 annotation 的地方,便能影響框架使之把控制權交給你,便能演出剛剛 python 裡的 @get('/index')
精彩戲碼
來看看 python decorator
在來看看 python 的小老鼠,其實是與 java annotation 有所不同,以往這種想對程式添加東西的動作,在設計模式裡發展出了一個叫做裝飾者模式的東西,使這種添加的動作不會太過難看,所以 python 直接使用 decorator 作為命名啦。
寫一個小小的範例如下
def log(func):
print("func name:", func.__name__)
return func
@log
def hello():
print("hello")
hello()
在此可以看到我寫了一個 log 的 function ,這個功能只是把被 log 標記過的 function ,在被呼叫的時候記住一下他的名字。
在這裡的呼叫 hello()時其實它的功能就是轉換成如下面這般形式
log(hello)()
是請 log 加工一下我的 hello function ,還給我一個加工過的 hello function ,而透過 decorator 可以把這醜陋的加工弄得漂亮一些。
而 code 可以很專注在自己的宣告上面,而 log 就變成了第二級需要注意的資訊,對於開發者大概就知道「喔,大概是要讓這個 function 被紀錄一下吧」,可以很明顯的看到能將眼睛的注意力分為兩種不同的等級。
小結論
有些人會覺得這種小小的 meta 功能根本不足以說嘴,但我覺得,多了 annotation 或是 decorator 其實能夠讓程式的閱讀性提升,而且可以少額外寫出一個設定檔的時間,因此我實在不覺得小老鼠是個應該被無視的功能呀 ~