MST
星途 面试题库

面试题:Angular服务的设计与依赖注入原理

阐述Angular服务在应用架构中的作用,以及依赖注入是如何实现的。假设有一个用户认证服务,在多个组件中都需要使用该服务进行用户认证状态检查,你如何设计这个服务并实现依赖注入,保证服务的单例性和可测试性?
17.8万 热度难度
前端开发Angular

知识考点

AI 面试

面试题答案

一键面试

Angular服务在应用架构中的作用

  1. 代码复用:服务允许将通用的功能逻辑封装起来,多个组件可以共享这些功能,避免在每个组件中重复编写相同的代码。例如,数据获取逻辑、用户认证逻辑等都可以放在服务中。
  2. 分离关注点:遵循单一职责原则,将不同功能模块划分到各自的服务中,使得组件的职责更加清晰。组件专注于处理视图相关的逻辑,而服务负责处理业务逻辑、数据访问等其他方面的逻辑。
  3. 管理全局状态:服务可以作为存储和管理应用全局状态的地方。例如,用户登录状态、应用配置等信息可以在服务中维护,不同组件可以通过服务获取和更新这些状态。

依赖注入的实现原理

  1. 容器:Angular有一个依赖注入容器,它负责创建、管理和提供依赖对象。这个容器是一个树形结构,根注入器位于顶部,每个组件也有自己的注入器,形成注入器树。
  2. 注册提供商:在应用的模块(NgModule)或组件中,通过providers数组注册服务提供商。提供商告诉注入器如何创建服务实例,例如使用class关键字指定服务类,也可以使用工厂函数、值对象等方式。
  3. 解析依赖:当一个组件需要某个服务(即依赖)时,它会向自己的注入器请求该服务。注入器首先在自己的范围内查找提供商,如果找不到,则向上级注入器查找,直到在根注入器中找到或返回null。如果找到了提供商,注入器会根据提供商的定义创建服务实例(如果尚未创建),并将其返回给组件。

用户认证服务设计与依赖注入实现

  1. 创建用户认证服务
    import { Injectable } from '@angular/core';
    
    @Injectable({
      providedIn: 'root'
    })
    export class AuthService {
      private isAuthenticated = false;
    
      public checkAuthStatus(): boolean {
        return this.isAuthenticated;
      }
    
      public login(): void {
        // 模拟登录逻辑
        this.isAuthenticated = true;
      }
    
      public logout(): void {
        // 模拟登出逻辑
        this.isAuthenticated = false;
      }
    }
    
    • @Injectable({ providedIn: 'root' }) 表示该服务在根注入器中提供,保证了服务的单例性,整个应用只有一个该服务的实例。
  2. 在组件中使用依赖注入
    import { Component } from '@angular/core';
    import { AuthService } from './auth.service';
    
    @Component({
      selector: 'app - my - component',
      templateUrl: './my - component.html'
    })
    export class MyComponent {
      constructor(private authService: AuthService) {}
    
      public checkUserAuth(): void {
        const isAuth = this.authService.checkAuthStatus();
        console.log('User is authenticated:', isAuth);
      }
    }
    
    • 在组件的构造函数中,通过类型声明(private authService: AuthService),Angular的依赖注入系统会自动将AuthService的实例注入到组件中。

保证服务的可测试性

  1. 单元测试:可以使用jestkarma等测试框架对AuthService进行单元测试。在测试中,可以创建AuthService的模拟实例,测试其方法的逻辑。
    import { TestBed } from '@angular/core/testing';
    import { AuthService } from './auth.service';
    
    describe('AuthService', () => {
      let service: AuthService;
    
      beforeEach(() => {
        TestBed.configureTestingModule({});
        service = TestBed.inject(AuthService);
      });
    
      it('should be created', () => {
        expect(service).toBeTruthy();
      });
    
      it('should return false for initial auth status', () => {
        const isAuth = service.checkAuthStatus();
        expect(isAuth).toBeFalse();
      });
    
      it('should set authentication status to true after login', () => {
        service.login();
        const isAuth = service.checkAuthStatus();
        expect(isAuth).toBeTrue();
      });
    
      it('should set authentication status to false after logout', () => {
        service.login();
        service.logout();
        const isAuth = service.checkAuthStatus();
        expect(isAuth).toBeFalse();
      });
    });
    
    • 通过TestBed可以模拟Angular的依赖注入环境,方便对服务进行单元测试。
  2. 组件测试:在测试使用AuthService的组件时,可以使用Mock对象来替换真实的AuthService,这样可以控制服务的行为,便于测试组件在不同认证状态下的表现。
    import { ComponentFixture, TestBed } from '@angular/core/testing';
    import { MyComponent } from './my - component';
    import { AuthService } from './auth.service';
    
    class MockAuthService {
      checkAuthStatus() {
        return true;
      }
    }
    
    describe('MyComponent', () => {
      let component: MyComponent;
      let fixture: ComponentFixture<MyComponent>;
    
      beforeEach(() => {
        TestBed.configureTestingModule({
          declarations: [MyComponent],
          providers: [
            { provide: AuthService, useClass: MockAuthService }
          ]
        });
        fixture = TestBed.createComponent(MyComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
      });
    
      it('should create', () => {
        expect(component).toBeTruthy();
      });
    
      it('should detect authenticated user', () => {
        const isAuth = component.authService.checkAuthStatus();
        expect(isAuth).toBeTrue();
      });
    });
    
    • 通过providers数组中的{ provide: AuthService, useClass: MockAuthService },在组件测试环境中用MockAuthService替换了真实的AuthService,方便测试组件与服务的交互。