[Angular 2] 翻譯:Angular 2 服務:是不是單例?
這篇文章的目的是幫助大家理解 Angular 2 基於依賴注入的作用域如何工作,需要明白元件,服務等相關知識以及對依賴注入的基本瞭解。
– Angular 2 服務是不是單例?
– 某種意義上來說,是的。。。
– 兄弟,你說的貌似沒什麼幫助啊。。。
– 那好吧,讓我們從頭說起。。。
Angular 1.x 服務非常流行。每一個服務都有一個具體例項,它可以被注入並在需要使用的地方來使用。Angular 2 的服務也照樣不錯,讓我們探討這個話題吧。
– 兄弟,是時候言歸正傳啦。。。
– 好的,讓我們先從一個簡單的服務開始說起,這是讓人難以忘記的反例家族的一員。。。
服務儘可能簡單
// a very simple counter service import { Injectable } from '@angular/core'; @Injectable() export class SimpleCounterService { private count: number = 0; inc() { this.count++; } dec() { this.count--; } getCount(): number { return this.count; } }
如果我們想在整個應用程式中使用這個服務,就像我們在 Angular 1 做的那樣。我們不需要做更多,只是把它作為 BootStrap 方法的第二個引數就行。
bootstrap(App, [CounterService]);
接下來,我們可以使用任何有用的服務使用任何的元件,比如:
import { Component } from '@angular/core'; import { SimpleCounterService } from './simple_counter.service'; @Component({ selector: 'simple-counter', template: ` <divclass="simple-counter"> <button (click)="dec()">-</button> {{ getCount() }} <button (click)="inc()">+</button> </div> ` }) export class SimpleCounterComponent { constructor(private counterService: SimpleCounterService) { } dec() { this.counterService.dec(); } inc() { this.counterService.inc(); } getCount(): number { return this.counterService.getCount(); } }
非常簡單。
– 兄弟,這沒意義啊。每個計數器元件的值都是一樣的,如果我需要更多的計數器呢?
– 說的很對。當我們遇到一個這樣的服務時,這是最重要的問題之一。讓我們採用在 Angular 1 解決該問題的方案:給每個計數器一個唯一識別符號。。。
經過唯一識別符號處理過的服務
我們的服務。。。
// a very simple counter service import { Injectable } from '@angular/core'; @Injectable() export class OldschoolCounterService { private counters = {}; inc(counterId) { this.getCounterById(counterId).count++; } dec(counterId) { this.getCounterById(counterId).count--; } getCount(counterId): number { return this.getCounterById(counterId).count; } deleteCounter(counterId) { deletethis.counters[counterId]; } private getCounterById(id): Object { if (! this.counters[id]) { this.counters[id] = { count: 0 }; } return this.counters[id]; } }
不要忘記使用 bootstrap 方法:
bootstrap(App, [OldschoolCounterService]);
我們的元件。。。
import { Component, Input, OnDestroy } from '@angular/core'; import { OldschoolCounterService } from './oldschool_counter.service'; @Component({ selector: 'oldschool-counter', template: ` <divclass="simple-counter"> <button (click)="dec()">-</button> {{ getCount() }} <button (click)="inc()">+</button> </div> ` }) export class OldschoolCounterComponent implements OnDestroy { @Input() private counterId: string; constructor(private counterService: OldschoolCounterService) { } dec() { this.counterService.dec(this.counterId); } inc() { this.counterService.inc(this.counterId); } getCount(): number { return this.counterService.getCount(this.counterId); } ngOnDestroy() { // we do not want to remember the state of the component, // so we delete the counter from the service this.counterService.deleteCounter(this.counterId); } }
– 現在執行得不錯,就像我們想要的那樣,每個計數器都有不同的值
– 是的,但是。。。
– 我不覺得還有什麼問題啊。。。
– 靈活性和可複用性怎麼樣?
– 我覺得還好吧。我只是剛設定了ID,哦,如果。。。
– 對,就是這個。
這不是這兒唯一的問題。最明顯的問題在於我們需要非常小心,不能使用相同的 ID 給不同的元件。這個問題還好解決。更大的問題在於耦合在一起的元件和服務不嚴密。元件需要提供一個 ID,服務總是需要基於該 ID 來執行。所以我們用特定方法來限制從而實施該服務。
– 好,那該怎麼做?
– 這是 Angular 2 採用的方法:正如我之前提到的 Angular 2 的服務是某種單例。。。讓我們來看看到底是什麼意思
Angular 2 方式的服務
在 Angular 2 中,服務是單例 scopewise 的。
– 為你的健康乾杯!
裝飾器元件有一個叫 providers 的屬性。它工作方式完全和 bootstrap 函式第二個引數相同,但是該服務在元件範圍內建立了一個新的例項,因此,元件與每個下級元件都會使用這個新的例項。(除非他們不使用自有的服務上的例項,不過這就另說啦。)
讓我們看看新的計陣列件。。。
import { Component } from '@angular/core'; import { SimpleCounterService } from './simple_counter.service'; @Component({ selector: 'newage-counter', template: ` <divclass="newage-counter"> <button (click)="dec()">-</button> {{ getCount() }} <button (click)="inc()">+</button> </div> `, providers: [ SimpleCounterService ] }) export class NewageCounterComponent { constructor(private counterService: SimpleCounterService) { } dec() { this.counterService.dec(); } inc() { this.counterService.inc(); } getCount(): number { return this.counterService.getCount(); } }
– 那服務呢?
– 我們簡單地使用 SimpleCounterService 就好啦。
由於我們在元件中有一個專門的例項服務,每個元件將會有自身的值。
就像我們看到的 scopewise 單例服務設計模式是 Angular 2 的一個令人難以置信的功能。它給程式碼更多的靈活性,使其更容易重用及維護。而且我們只是說了表面上的一點點。