haizlin / fe-interview

前端面试每日 3+1,以面试题来驱动学习,提倡每日学习与思考,每天进步一点!每天早上5点纯手工发布面试题(死磕自己,愉悦大家),6000+道前端面试题全面覆盖,HTML/CSS/JavaScript/Vue/React/Nodejs/TypeScript/ECMAScritpt/Webpack/Jquery/小程序/软技能……
http://www.h-camel.com
MIT License
25.04k stars 3.24k forks source link

[angular] 第1879天 请说说在Angular中提供者,服务和工厂之间有什么区别? #5841

Open haizhilin2013 opened 1 month ago

haizhilin2013 commented 1 month ago

第1879天 请说说在Angular中提供者,服务和工厂之间有什么区别?

3+1官网

我也要出题

llccing commented 6 days ago

在 Angular 中,提供者(Provider)、服务(Service)和工厂(Factory)是依赖注入(Dependency Injection)机制的核心概念。它们之间的区别在于它们的定义方式、使用场景以及创建实例的方式。下面详细解释这些概念及其区别。

提供者(Provider)

提供者是 Angular 依赖注入系统中用于配置如何创建和提供依赖对象的机制。提供者可以在模块、组件或指令的 providers 数组中配置。

提供者的类型

  1. 类提供者(Class Provider): 使用类来定义提供者。Angular 会使用 new 操作符来实例化这个类。

    @Injectable({
     providedIn: 'root'
    })
    export class MyService {
     constructor() { }
    }
  2. 值提供者(Value Provider): 使用一个预定义的值来提供依赖。

    const MY_VALUE = { key: 'value' };
    
    @NgModule({
     providers: [{ provide: 'MY_VALUE', useValue: MY_VALUE }]
    })
    export class AppModule { }
  3. 工厂提供者(Factory Provider): 使用一个工厂函数来创建依赖对象。

    export function myFactory() {
     return new MyService();
    }
    
    @NgModule({
     providers: [{ provide: MyService, useFactory: myFactory }]
    })
    export class AppModule { }
  4. 别名提供者(Alias Provider): 使用另一个令牌来提供依赖对象,即依赖对象的别名。

    @NgModule({
     providers: [{ provide: 'AnotherService', useExisting: MyService }]
    })
    export class AppModule { }

服务(Service)

服务是一个类,通常用来封装应用程序的业务逻辑和数据访问。服务类使用 @Injectable 装饰器来标记,以便 Angular 的依赖注入系统可以注入它们。

服务的定义

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class MyService {
  constructor() { }

  getData() {
    return 'some data';
  }
}

在上面的示例中,MyService 被定义为一个服务,并且通过 providedIn: 'root' 选项在根注入器中提供,这意味着它是一个单例服务。

工厂(Factory)

工厂是一个函数,用于创建和返回依赖对象。工厂函数可以包含一些逻辑,以便根据需要动态创建对象。工厂通常与工厂提供者一起使用。

工厂的定义

export function myFactory() {
  return new MyService();
}

@NgModule({
  providers: [{ provide: MyService, useFactory: myFactory }]
})
export class AppModule { }

在上面的示例中,myFactory 函数被用作工厂函数,通过 useFactory 提供给 MyService

区别和使用场景

  1. 提供者(Provider)

    • 定义方式:通过 providers 数组配置。
    • 使用场景:用于配置如何创建和提供依赖对象,可以是类、值、工厂函数或别名。
  2. 服务(Service)

    • 定义方式:通常是一个使用 @Injectable 装饰器的类。
    • 使用场景:用于封装业务逻辑和数据访问,通常通过依赖注入提供给组件或其他服务。
  3. 工厂(Factory)

    • 定义方式:一个函数,通常与工厂提供者一起使用。
    • 使用场景:用于动态创建依赖对象,特别是在需要一些创建逻辑或条件的情况下。

总结

通过理解这些概念及其区别,你可以更好地设计和构建 Angular 应用程序的依赖注入系统,提升代码的可维护性和重用性。

llccing commented 6 days ago

对于4种类型的提供者可能会有点迷惑,接下来通过4个想详细的例子有个更清晰的了解:

当然,实际例子能更好地帮助理解提供者的四种类型及其使用场景。下面是一些具体的例子:

1. 类提供者(Class Provider)

场景:你有一个服务类 LoggingService,它负责记录日志信息。你希望在应用程序的不同部分使用这个服务。

示例

// logging.service.ts
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class LoggingService {
  log(message: string) {
    console.log(message);
  }
}

// app.component.ts
import { Component } from '@angular/core';
import { LoggingService } from './logging.service';

@Component({
  selector: 'app-root',
  template: '<h1>My App</h1>'
})
export class AppComponent {
  constructor(private loggingService: LoggingService) {
    this.loggingService.log('AppComponent initialized');
  }
}

2. 值提供者(Value Provider)

场景:你有一些静态的配置信息,例如 API 的基 URL,你希望在应用程序中共享这些配置。

示例

// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';

const API_CONFIG = { baseUrl: 'https://api.example.com' };

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule],
  providers: [{ provide: 'API_CONFIG', useValue: API_CONFIG }],
  bootstrap: [AppComponent]
})
export class AppModule { }

// app.component.ts
import { Component, Inject } from '@angular/core';

@Component({
  selector: 'app-root',
  template: '<h1>My App</h1>'
})
export class AppComponent {
  constructor(@Inject('API_CONFIG') private config: any) {
    console.log('API Base URL:', this.config.baseUrl);
  }
}

3. 工厂提供者(Factory Provider)

场景:你有一个服务 UserService,它需要根据某些条件动态创建。比如,你希望在服务创建时注入一个依赖 HttpClient,并根据环境变量选择不同的 API 端点。

示例

// user.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable()
export class UserService {
  constructor(private http: HttpClient, private apiUrl: string) { }

  getUser() {
    return this.http.get(`${this.apiUrl}/user`);
  }
}

// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule, HttpClient } from '@angular/common/http';
import { AppComponent } from './app.component';
import { UserService } from './user.service';

export function userServiceFactory(http: HttpClient) {
  const apiUrl = environment.production ? 'https://api.prod.com' : 'https://api.dev.com';
  return new UserService(http, apiUrl);
}

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, HttpClientModule],
  providers: [{ provide: UserService, useFactory: userServiceFactory, deps: [HttpClient] }],
  bootstrap: [AppComponent]
})
export class AppModule { }

// app.component.ts
import { Component } from '@angular/core';
import { UserService } from './user.service';

@Component({
  selector: 'app-root',
  template: '<h1>My App</h1>'
})
export class AppComponent {
  constructor(private userService: UserService) {
    this.userService.getUser().subscribe(user => console.log(user));
  }
}

4. 别名提供者(Alias Provider)

场景:你有一个服务 AuthService,它实现了一个 IAuthService 接口。你希望通过接口注入服务,以便将来可以轻松替换实现。

示例

// auth.service.ts
import { Injectable } from '@angular/core';

export interface IAuthService {
  login(username: string, password: string): void;
}

@Injectable({
  providedIn: 'root'
})
export class AuthService implements IAuthService {
  login(username: string, password: string) {
    console.log('User logged in');
  }
}

// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { AuthService, IAuthService } from './auth.service';

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule],
  providers: [{ provide: IAuthService, useExisting: AuthService }],
  bootstrap: [AppComponent]
})
export class AppModule { }

// app.component.ts
import { Component } from '@angular/core';
import { IAuthService } from './auth.service';

@Component({
  selector: 'app-root',
  template: '<h1>My App</h1>'
})
export class AppComponent {
  constructor(private authService: IAuthService) {
    this.authService.login('user', 'password');
  }
}

总结

这些实际例子展示了不同提供者类型的具体应用场景,帮助你理解它们的使用方式和存在的理由。