距離上一篇關於 decorator 的文章已經是 2017 一月份的事情了,時間過真快,那時候來不知道能拿 decorator 做什麼,現在終於有一個還不錯的使用情境
讓程式碼講話
開發 app 有時候會希望記錄某功能的使用量,常見的作法就是打一發 API 做記錄的動作,而這其實是可以透過 decorator 的方式封裝起來,然後讓任何需要記錄的 function 使用,以下就用程式碼說話了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| import { AppModule } from '../app.module'; import { LogService } from '../my-feature/log.service';
export function Logger(typeName: string) { return function ( target: Object, key: string | symbol, descriptor: PropertyDescriptor ) { const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) { const service = AppModule?.injector?.get(LogService); if (!!service) { service.recordUsage(typeName); } };
return originalMethod.apply(this, arguments); }; }
|
- line 4: 如果想要 decorator 能接受外部傳進來的值,就可以在這邊定義
- line 10: 保留被 decorated 的 function,等等在第 line 19 會用到
- line 12: 覆寫原本的 function
- line 13: 從
AppModule
取得 injector,可透過 injector 拿到有註冊到 RootModule
的 service
- line 19: 繼續執行原本 function 的行為
1 2 3 4 5 6 7
| ... export class AppModule { static injector: Injector; constructor(injector: Injector) { AppModule.injector = injector; } }
|
- 建立一個 static 變數讓自訂的 decorator 內可以使用
基本上,上面就已經完成了一個 Decorator 的開發了,當然那個 logService
就是自行發揮了
至於如何使用,範例如下
1 2 3 4
| @Logger('AppComponent') c(msg: string) { console.info('clicked', msg); }
|
參考資料