Angular学习笔记四之依赖注入与服务

一、依赖注入

(一)依赖注入理解

  1. 先来看一段代码:
class Engine {
    
    
    // Engine类的构造函数,需要接受一个number类型的参数
    constructor(speed: number) {
    
    
    }
}

class Car {
    
    
    private engine: Engine; // 声明一个私有属性,类型为Engine
    constructor() {
    
    
        // 在构造函数中实例化Engine
        this.engine = new Engine(200);
    }
}

在这段代码中,Car类里有一个私有属性engine,是Engine类的实例对象,此时这个属性的创建过程就会严重依赖Engine类的定义,如果Engine类需要接受的参数个数或类型发生改变,就需要立马修改engine属性的创建代码,代码的耦合度过高。

  1. 依赖注入就是为了降低代码耦合度而提出来的概念。依赖注入(Dependency Injection),简称DI,类之间的依赖关系由容器来负责。看下面一段代码:
class Engine {
    
    
    constructor(speed: number) {
    
    }
}
// 在类的外部实例化Engine类
const engine = new Engine(200);
class Car {
    
    
    private engine: Engine;
    constructor(engine: Engine) {
    
    
        // 直接使用
        this.engine = engine;
        console.log(engine)
    }
}
const car = new Car(engine)

在类的外部创建engine,这样Car类就不要管engine的传参问题,就不需要与Engine类耦合了。对象的创建过程Angular内部已经帮我们实现好了,所以我们在使用服务时,不需要再次创建,只要在constructor的参数列表中声明并且使用变量接收即可。

(二)Injector的创建和使用

  1. 概念
    Angular有自己的DI框架帮我们实现类的实例化。我们只需要通过简单的代码就可以实现复杂的依赖注入。
    Angular的DI框架主要有四个重要的概念:
    1. Dependency 组件要依赖的实例对象,即服务的实例对象
    2. Token 获取服务实例对象的标识。Angular内部维护了很多的实例对象,在获取时需要通过Token来判断要获取哪一个实例对象
    3. Injector 注入器,负责维护并创建实例对象,并且要找到组件需要的实例对象,通过参数的方式传递给组件
    4. Provider 用来配置注入器的对象,指定创建服务实例对象的类,以及指定Token
  2. Injector 注入器
    1. 创建注入器
      在app.moudule.ts根模块中引入ReflectiveInjector模块
    import {
          
          ReflectiveInjector} from '@angular/core';
    
    虚拟一个服务类,创建一个注入器
    class injectorService {
          
          
    constructor() {
          
          }
    run(){
          
          
            console.log('run')
        }
    }
    
    // 创建注入器,接受一个数组,数组里放服务类
    const injector = ReflectiveInjector.resolveAndCreate([injectorService])
    
    1. 获取服务实例,并且运行实例方法
    // 向get中传递Token标识,Token就是这个类,返回值就是这个类的实例对象
    const myInjector = injector.get(injectorService)
    myInjector.run()
    
    控制台成功运行了实例的方法:
    在这里插入图片描述
    3. 同一个注入器不会重复创建一个服务的实例,创建的同时就会缓存这个实例,因此服务是单例模式
    const myInjector1 = injector.get(injectorService)
    const myInjector2 = injector.get(injectorService)
    console.log(myInjector1 === myInjector2) // true
    
    1. 不同的注入器创建出来的实例不一样
    // 创建子级注入器
    const childInjector = injector.resolveAndCreateChild([injectorService])
    const myInjector1 = injector.get(injectorService)
    const myInjector3 = childInjector.get(injectorService)
    console.log(myInjector1 === myInjector3) // false
    
    1. 注入器查找服务实例的方式类似于作用域链,当在当前注入器中找不到时,会向父级注入器查找,都找不到才会创建新的实例
    // 创建注入器
    const injector = ReflectiveInjector.resolveAndCreate([injectorService])
    // 子级注入器不传服务
    const childInjector = injector.resolveAndCreateChild([])
    const myInjector1 = injector.get(injectorService)
    // 当前注入器中没有找到,会向上级注入器查找
    const myInjector3 = childInjector.get(injectorService)
    console.log(myInjector1 === myInjector3)  // true
    
  3. Provider
    上面创建注入器的形式其实是一种简写方式,下面来看完整的写法
    通过Provide指定获取实例对象的标识,也就是token。当provide和useClass相同的时候,就可以直接写类
    	const injector = ReflectiveInjector.resolveAndCreate([{
          
          
    	    provide: "myInjectorService",
    	    useClass: injectorService
    	}])
    	const myInjector1 = injector.get("myInjectorService")
    
    useClass表明当前注入器存储的是一个类
    注入器不仅可以用来存储类,也可以用来存储对象,用注入器存储的对象往往是唯一的,不可变的
    const injector = ReflectiveInjector.resolveAndCreate([{
          
          
        provide: "user",
        useValue: Object.freeze({
          
          
            userName:'张三',
            userToken:'123456'
        })
    }])
    const user = injector.get('user')
    

(二)服务

  1. 服务的创建与引入
    • 使用cli提供的命令行工具创建服务:ng g s shared/user ,会在shared模块下创建一个服务
      在这里插入图片描述
    • 书写服务代码
      import {
              
               Injectable } from '@angular/core';
      @Injectable({
              
              
        providedIn: 'root'
      })
      export class UserService {
              
              
        constructor() {
              
               }
        getUser() {
              
              
          return {
              
              
            name: '张三',
            age: 20,
            address: '北京市'
          }
        }
      }
      
    • 在组件类中引入服务
    import {
          
          UserService} from "../../user.service";
    
    public user = this.userService.getUser();
    ngOnInit() {
          
          
        console.log(this.user)
    }
    

猜你喜欢

转载自blog.csdn.net/weixin_45855469/article/details/130378270