如果一个对象A需要依赖对象B,那么对象A不需要明确实例化对象B,B会由外部机制注入进来。
1.png
<1>提供器声明在模块中
1.新建一个项目
ng new projectname
2.新建组件product1
ng g component product1
3.生成服务service
ng g service shared/product
//生成一个名叫product的服务,放在了shared文件夹下
ps:
若报错
too many symbolic links encountered
解决办法:
删除node_modules文件夹, 重新npm install
4.目录结构
5.编写服务product.service.ts
import { Injectable } from '@angular/core';
/*
@Injectable装饰器作用:
让ProductService能够将别的服务注入到它的构造函数constructor中
*/
@Injectable()
export class ProductService {
constructor() { }
//3.声明getProduct()方法,返回Product对象
getProduct():Product {
//4.返回--这里直接new了一个对象
return new Product(1,"iphone7",8799,"手机");
}
}
// 1.定义一个商品信息类product
export class Product {
// 2.构造函数:定义里面的字段
constructor(
public id:number,
public title:string,
public price:number,
public desc:string
){}
}
6.修改模块声明--app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { Product1Component } from './product1/product1.component';
// 2.引入
import { ProductService } from './shared/product.service';
@NgModule({
declarations: [
AppComponent,
Product1Component
],
imports: [
BrowserModule
],
//1.提供器--添加声明
providers: [ProductService],
bootstrap: [AppComponent]
})
export class AppModule { }
7.改写组件--product1.component.ts
import { Component, OnInit } from '@angular/core';
//4.引入Product,ProductService
import { Product,ProductService } from '../shared/product.service';
@Component({
selector: 'app-product1',
templateUrl: './product1.component.html',
styleUrls: ['./product1.component.css']
})
export class Product1Component implements OnInit {
//1.声明Product类型的组件用来接收从服务中获取到的数据
product: Product;
//2.注入器:构造函数中通过依赖注入,声明token是ProductService的一个服务
constructor(private productService:ProductService) { }
ngOnInit() {
//3.使用服务的getProduct()方法获取数据,赋给本地product变量
this.product = this.productService.getProduct();
}
}
8.修改组件的模版,用于展示信息--product1.component.html
<div>
<h4>商品详情</h4>
<h4>id:{{product.id}}</h4>
<h4>名称:{{product.title}}</h4>
<h4>价格:{{product.price}}</h4>
<h4>描述:{{product.desc}}</h4>
</div>
9.修改主组件模版,来显示商品组件--app.component.html
<div>
<div>依赖注入例子</div>
<div>
<app-product1></app-product1>
</div>
</div>
<2>提供器声明在组件中
上面的例子中,提供器是声明在app.module.ts中的,提供器也可以声明在组件中,下面是例子。
1.声明第二个组件
ng g component product2
2.生成另一个服务
ng g service shared/anotherProduct
3.编写anotherProduct服务--another-product.service.ts
import { Injectable } from '@angular/core';
//4.import ProductService,Product
import { ProductService,Product } from './product.service';
@Injectable()
//1.实现ProductService,让AnotherProductService和ProductService有相同方法
export class AnotherProductService implements ProductService{
//2.实现ProductService中的getProduct()方法
getProduct():Product {
//3.同样返回一个商品对象
return new Product(2,"huawei",3000,"华为");
}
constructor() { }
}
4.修改模块声明--app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { Product1Component } from './product1/product1.component';
import { ProductService } from './shared/product.service';
//2.引入
import { Product2Component } from './product2/product2.component';
@NgModule({
declarations: [
AppComponent,
Product1Component,
//1.引入
Product2Component
],
imports: [
BrowserModule
],
providers: [ProductService],
bootstrap: [AppComponent]
})
export class AppModule { }
5.编写product2.component.ts
构造器部分与product1.component.ts相同,唯一不同的是多声明了一个providers
import { Component, OnInit } from '@angular/core';
import { Product,ProductService } from '../shared/product.service';
//4.引入AnotherProductService
import { AnotherProductService } from '../shared/another-product.service';
@Component({
selector: 'app-product2',
templateUrl: './product2.component.html',
styleUrls: ['./product2.component.css'],
//2.在组件中声明providers
providers:[{
//3.不同的是使用的是AnotherProductService服务
provide:ProductService,useClass:AnotherProductService
}]
})
export class Product2Component implements OnInit {
//1.与produce1相同
product: Product;
constructor(private productService:ProductService) { }
ngOnInit() {
this.product = this.productService.getProduct();
}
}
6.编写product2.component.html
与product1模版相同
<div>
<h4>商品详情</h4>
<h4>id:{{product.id}}</h4>
<h4>名称:{{product.title}}</h4>
<h4>价格:{{product.price}}</h4>
<h4>描述:{{product.desc}}</h4>
</div>
7.编写app.component.html
<div>
<div>依赖注入例子</div>
<div>
<app-product1></app-product1>
<!-- 引入product2组件 -->
<app-product2></app-product2>
</div>
</div>
提供器作用规则
1.当提供其声明在模块中时(app.module.ts),是对所有模块可见的,所有模块都可以注入
2.当一个提供器声明在组件中时,例如(product2.component.ts),这个提供器只对声明它的组件及
其子组件可见
3.当声明在组件中的提供器和模块中的提供器具有相同的token时,组件中的提供器,
例如(product2.component.ts)会覆盖声明在模块中的提供器
4.一般情况下应优先将提供器声明在模块中(app.module.ts),除非某提供器必须对其他组件不可见时
才声明在组件中
<3>服务之间如何互相注入
1.生成新的服务logger
ng g service shared/logger
2.编写logger.service.ts
import { Injectable } from '@angular/core';
@Injectable()
export class LoggerService {
constructor() { }
//1.方法log(),接收一个string类型的message
log(message:string) {
//2.打印
console.log(message);
}
}
3.编写product.service.ts--在其构造函数中注入logger服务
import { Injectable } from '@angular/core';
//2.引入
import { LoggerService } from './logger.service';
@Injectable()
export class ProductService {
//1.注入logger服务
constructor(private logger:LoggerService) { }
getProduct():Product {
//3.调用logger中的log方法
this.logger.log("log message");
return new Product(1,"iphone7",8799,"手机");
}
}
export class Product {
constructor(
public id:number,
public title:string,
public price:number,
public desc:string
){}
}
4.app.module.ts模块中声明logger提供器--让logger能被别的服务注入
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { Product1Component } from './product1/product1.component';
import { ProductService } from './shared/product.service';
import { Product2Component } from './product2/product2.component';
// 2.引入
import { LoggerService } from './shared/logger.service';
@NgModule({
declarations: [
AppComponent,
Product1Component,
Product2Component
],
imports: [
BrowserModule
],
//1.提供器--添加声明LoggerService
providers: [ProductService,LoggerService],
bootstrap: [AppComponent]
})
export class AppModule { }
5.结果--控制台中
PS:
1.只有声明了@Injectable()装饰器的服务才能注入其他服务,建议所有服务都声明@Injectable()装饰器。
2.组件能够注入服务的原因是声明了@Component装饰器,而这个装饰器是@Injectable()装饰器的子类
<4>使用工厂提供器和值声明提供器
1.修改product2.component.ts
删除以上例子中product2组件中的providers声明,使product1和product2共用模块中app.module.ts声明的service
删除
providers:[{
//3.不同的是使用的是AnotherProductService服务
provide:ProductService,useClass:AnotherProductService
}]
2.修改app.module.ts的提供器声明
把providers: [ProductService,LoggerService],
bootstrap: [AppComponent]
改成
providers: [{
provide:ProductService,
//工厂提供器
useFactory:() => {
let logger = new LoggerService();
//设置随机数来判断使用哪个服务
let flag = Math.random() > 0.5;
if(flag){
return new ProductService(logger);
}else{
return new AnotherProductService(logger);
}
}
},LoggerService],
bootstrap: [AppComponent]
})
3.修改another-product.service.ts
import { Injectable } from '@angular/core';
import { ProductService,Product } from './product.service';
import { LoggerService } from './logger.service';
@Injectable()
export class AnotherProductService implements ProductService{
getProduct():Product {
return new Product(2,"huawei",3000,"华为");
}
//因为实现了ProductService,所以与ProductService的构造函数一样
constructor(public logger:LoggerService) { }
}
4.修改product.service.ts
把logger改为public
constructor(public logger:LoggerService) { }
5.结果
根据随机数的不同,实现的服务不一样
PS:
在这个例子中produce1和product2组件使用的服务永远是相同的,因为工厂方法对象是一个单例对象,它只会在创建第一个需要注入的对象时被调用一次,然后在整个应用中,所有被注入的ProductService的实例,都是同一个对象
问题1
在工厂方法中手工实现了一个LoggerService,意味着这个工厂方法与LoggerService类是紧密耦合在一起的
let logger = new LoggerService();
解决
在product的工厂方法useFactory中去使用LoggerService提供器,修改代码:
providers: [{
provide:ProductService,
//2.把logger作为参数传进去,
useFactory:(logger:LoggerService) => {
let flag = Math.random() > 0.5;
if(flag){
return new ProductService(logger);
}else{
return new AnotherProductService(logger);
}
},
//1.声明第三个参数deps,用来声明工厂方法所依赖的参数
//3.在deps里添加LoggerService,表明需要依赖LoggerService
deps:[LoggerService]
},LoggerService],
问题2
当前实例化哪个对象使用flag随机数来判断的,在真实的项目中可能会依赖一个变量来判断,这个变量可能在不同环境和变量是不一样的
解决
变量也能像服务一样进行依赖注入
providers: [{
provide:ProductService,
// 2.加上第二个参数,这个参数自定义命名,对应的是 deps中的第二个参数
useFactory:(logger:LoggerService,IsT) => {
if(IsT){
return new ProductService(logger);
}else{
return new AnotherProductService(logger);
}
},
//3.添加提供器的token:Is_True
deps:[LoggerService,"Is_True"]
},LoggerService,
// 1.第三个提供器,声明了一个token是一个字符串,注入的就是明确的值flase
{
provide:"Is_True",useValue:false
}],
除了用具体值来定义一个提供器,也可以用一个对象来定义
providers: [{
provide:ProductService,
useFactory:(logger:LoggerService,IsT) => {
// 2.取对象中的isDev的值
if(IsT.isDev){
return new ProductService(logger);
}else{
return new AnotherProductService(logger);
}
},
deps:[LoggerService,"Is_True"]
},LoggerService,
{
//1.把Is_True改为对象,修改useValue
provide:"Is_True",useValue:{isDev:true}
}],
网友评论