Angular service 详解

6,172 阅读3分钟

Angular为什么需要service

  1. 组件应该是专注于展示层,所以需要service来获取数据和保存数据。
  2. 组件之间的通信需要service来协助完成。

众所周知,angular中service采用的是依赖注入,那什么是依赖注入呢?

依赖注入(DI)是一种设计模式

为什么需要依赖注入

从一个小例子说起

export class Car {

  public engine: Engine; // 引擎
  public tires: Tires; // 轮胎

  constructor() {
    this.engine = new Engine();
    this.tires = new Tires();
  }
}

//如果更换了引擎的构造函数,要传入气缸数,构造函数则要跟着改
  constructor() {
    this.engine = new Engine(12);
    this.tires = new Tires();
  }


上面创建了一个汽车类,但是这个类完全没有健壮性。假如引擎的构造函数改变了,构建引擎的时候需要传一个参数,我们就得去汽车类里面改变new Engine()这个使用。如果仅仅是需要改两个地方可能还能接受,但是如果引擎类还依赖别的零件,这么一层层的依赖关系,其中一个构造函数要发生改变了,可能会导致一连串的改变,会导致写出来的代码完全没有可维护性。轮胎也是如此,不同的汽车需要不同的轮胎,那么像上述这么写就不太灵活,没有通用性可言。

所以这样就需要依赖注入

export class Car {
    constructor(public engine: Engine, public tires: Tires) { }
    }

let car = new Car(new Engine(), new Tires());

这样 engine和tire 和car类就是分离的,只要你是传入的引擎和轮胎是满足要求的,那么这个car就是okay的。

class Engine2 {
  constructor(public cylinders: number) { }
}

// 如果需要一个12缸的引擎, 这样我们完全不用动car类。
let bigCylinders = 12;
let car = new Car(new Engine2(bigCylinders), new Tires());

依赖注入这种模式也为编写测试用例提供了方便,在测试car类的时候,你不必去关系轮胎细节,只要给出一个可用的轮胎就行。

上面解释了依赖注入是什么,以及为什么需要依赖注入。就是一个类从外界接受他所需要的依赖关系,而不是自己去创造它们。但是对于消费者,问题又来了。想要一辆车,就必须得有一个工厂来组装出一个车

import { Engine, Tires, Car } from './car';

export class CarFactory {
  createCar() {
    let car = new Car(this.createEngine(), this.createTires());
    car.description = 'Factory';
    return car;
  }

  createEngine() {
    return new Engine();
  }

  createTires() {
    return new Tires();
  }
}

这个模式看来起似乎没有问题,但是这只是简化的依赖,类似的引擎工厂类, 轮胎工厂类,相互调用,相互依赖,这会形成一个不可维护的🕸️

这个时候就需要一个依赖注入框架了。这个框架有一个叫注入器的东西,需要一个Car时, 只需要

let car = injector.get(Car);

这样消费者也不用去维护生产car的工厂类。并且car类本身也不管轮胎,引擎怎么来的。皆大欢喜。

angular中依赖注入模式

angular中采用的是分层依赖注入

angular的应用程序是一个组件树,每一个组件实例化都有自己的注入器providers。


组件在找service的时候会一直向上冒泡寻找,直到找到根组件AppComponent还没有找到的时候就会报错。

这样设计的好处:

  1. 便于组件之间的通信。顶层一点的组件可以统一控制多个子组件的对同一个数据的操作。
  2. 增加复用。可以抽出多个底层组件复用的service写在上层组件中。


angular中service的小知识

  1. 生成一个module的service。 ng g service test --module=app
  2. src/app/test.service.ts
    
    import { Injectable } from '@angular/core';
    
    @Injectable()
    export class TestService {
      constructor() { }
    }
    
  3. 采用 @Injectable()装饰器,这个东西告诉angular这个服务类可能本身注入了依赖,
  4. 组件本身是不管服务内部怎么运作。
  5. service是必须通过providers注入。
  6. 是可以在服务的构造函数中调用一些业务函数 ,但不是最佳实践。
  7. 服务在app内是单例的。