1. 程式人生 > >[Angular 2] 翻譯:Angular 2 服務:是不是單例?

[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 的一個令人難以置信的功能。它給程式碼更多的靈活性,使其更容易重用及維護。而且我們只是說了表面上的一點點。