Angular 为什么需要 service
组件应该是专注于展示层, 所以需要 service 来获取数据和保存数据.
组件之间的通信需要 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 还没有找到的时候就会报错.
这样设计的好处:
便于组件之间的通信. 顶层一点的组件可以统一控制多个子组件的对同一个数据的操作.
增加复用. 可以抽出多个底层组件复用的 service 写在上层组件中.
angular 中 service 的小知识
生成一个 module 的 service. ng g service test --module=app
- src/app/test.service.ts
- import { Injectable } from '@angular/core';
- @Injectable()
- export class TestService {
- constructor() { }
- }
采用 @Injectable()装饰器, 这个东西告诉 angular 这个服务类可能本身注入了依赖,
组件本身是不管服务内部怎么运作.
service 是必须通过 providers 注入.
是可以在服务的构造函数中调用一些业务函数 , 但不是最佳实践.
服务在 app 内是单例的.
来源: https://juejin.im/post/5ad70ab4f265da2389264115