依赖注入

依赖注入(DependencyInJection 简称DI)依然在线竞拍为例子

控制反转:Inversionof Control 简称:IOC

Varproducr =new Product();

product依赖Product

依赖注入模式及使用的好处,angular如何实现依赖注入

 

注入器的层级关系

 

 

松耦合和可重用性,提高可测试性

 


 

 

 

实现依赖注入:

注入器:每个组件都有一个注入器,负责注入组件需要的对象

注入器:

constructor( private productService:ProductService) {...}

提供器:不同的写法

providers:[{provider:ProductService,useClass:ProductService}]

providers:[ProductService]//如果provideruseClass一样可以简写成这样

 

providers:[{provider:ProductService,useClass:AnotherProductService}]

解释:联动注入器,其实真正的实例化是AnotherProductService,原因是注入器中的ProductService,根据提供器中的ProductService来匹配要注入的对象和提供器的,然后根据useClass提供什么类,就实例化什么类!(简洁一句话就是:真正的注入的是useClass这个类)

 

provider:[{provide:ProductService,useFactory:()=>{...}}]

解释:就是通过工厂方法返回的实例,然后将返回的实例注入到注入器中

 

 

实例演示:

 

新建一个项目ngnew di

 

新建组件ng gcomponent product1

 

新建服务ng gservice shared/product

 

修改product.service.ts

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

@Injectable()

export class ProductService {

constructor() { }

//添加的地方--------------------------------

getProduct():Product{

return new Product(0,"iPhone",5899,"最新版")

}

//--------------------------

}

//添加到类

export class Product{

constructor(

public id:number,

public title:string,

public price:number,

public desc:string

){

}

}

 

app.module.ts中引入

providers: [ProductService],

 

修改product1的控制器product1.component.ts

import { Component, OnInit } from '@angular/core';

import { Product, ProductService } from '../shared/product.service';

@Component({

selector: 'app-product1',

templateUrl: './product1.component.html',

styleUrls: ['./product1.component.css']

})

export class Product1Component implements OnInit {

//声明一个变量,然后在构造函数中通过依赖注入声明需要的服务

 product:Product;

 constructor(private productService:ProductService) { }

ngOnInit() {

 this.product=this.productService.getProduct();

}

}

 

图解:红框中的代码为添加代码


 

修改product1.component.html

<div>

<h1>商品详情</h1>

<h2>名称:{{product.title}}</h2>

<h2>价格:{{product.price}}</h2>

<h2>描述:{{product.desc}}</h2>

</div>

 

修改app.component.html

<div>

<div>

<h1>基本的依赖注入</h1>

</div>

<div>

<app-product1></app-product1>

</div>

</div>

 

运行程序:结果截图


 

新建组件ng g component product2

 

新建服务ng g service shared/anotherProduct

 

 

修改another-product.service.ts控制器

 

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

import { ProductService, Product } from './product.service';

@Injectable()

//实现productService接口

export class AnotherProductService implements ProductService{

getProduct(): Product {

return new Product(1,"三星手机",4899,"最新版手机");

}

constructor() { }

}

 

 

修改product2.component.ts控制器

 

import { Component, OnInit } from '@angular/core';

import { Product, ProductService } from '../shared/product.service';

import { AnotherProductService} from '../shared/another-product.service';

@Component({

selector: 'app-product2',

templateUrl: './product2.component.html',

styleUrls: ['./product2.component.css'],

//添加一个注入器,让他实例化AnotherProductService类,是another-product.service.ts中的一个类

providers:[{

provide:ProductService,useClass:AnotherProductService

}]

})

 

export class Product2Component implements OnInit {

product:Product;

constructor(private productService:ProductService) { }

ngOnInit() {

this.product=this.productService.getProduct();

}

}

 

修改product2.component.html

 

<div>

<h1>商品详情</h1>

<h2>名称:{{product.title}}</h2>

<h2>价格:{{product.price}}</h2>

<h2>描述:{{product.desc}}</h2>

</div>

修改app.component.html

 

<div>

<div>

<h1>基本的依赖注入</h1>

</div>

<div>

<app-product1></app-product1>

<app-product2></app-product2>

</div>

</div>

 

 

总结注入器的作用域规则

第一点:一个提供器声明在模块时,是对所有组件可见的,所有组件都是可以注入的

第二点:声明在组件内的时候,只对组件和子组件可见其他组件不能注入

第三点:声明在模块的提供器和声明在组件内的提供器时,组件内的可以覆盖模块中的    提供器

第四点:我们应该优先把提供器声明在模块中,只有需要对其他组件不可见时才声明在组件中,但这种情况是非常罕见的。

-------------------------------------------------

product.service.ts控制器

 

@Injectable()

export class ProductService {

constructor() { }

getProduct():Product{

return new Product(0,"iPhone",5899,"最新版")

}

}

 


 

图中的productService可以注入别的服务(通过构造函数将其他服务注入到本服务中),本服务能不能注入到别的服务是看本服务有没有在providers属性中声明决定的,

@Injectable()这个装饰器只要有@Injectable()服务就能将别的服务注入进来

 

@Injectable()

export classProductService {

 

@Injectable()这个装饰器的意思是,其他服务也可以注入到这个服务中,建议给每个服务都添加这个装饰器。

 

问题:为啥我组件上没有声明这个装饰器也可以注入服务,因为@Component装饰器是@Injectable()装饰器的子类。

 

而这个服务是否可以注入到其他服务中,是根据他是否声明在app.module.ts中的providers属性中决定的。

 

 

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';

 

@NgModule({

declarations: [

AppComponent,

Product1Component,

Product2Component

],

imports: [

BrowserModule

],

providers: [ProductService],

bootstrap: [AppComponent]

})

export class AppModule { }


 

服务之间如何互相注入

新建服务ng g service shared/logger

 

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

@Injectable()

export class LoggerService {

constructor() { }

log(message:string){

console.log(message);

}

}

修改 app.module.ts

providers: [ProductService,LoggerService],

修改product.service.ts

 

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

import { LoggerService } from './logger.service';

@Injectable()

export class ProductService {

constructor(private logger:LoggerService) { }

getProduct():Product{

this.logger.log("getproduct方法被调用");

return new Product(0,"iPhone",5899,"最新版")

}

}

export class Product{

constructor(

public id:number,

public title:string,

public price:number,

public desc:string

){

}

}

运行结果:

 

 

 

重构Auction

1、编写ProductService 包含3个方法:getProducts(),getProduct(id)以及            getCommentsForProduct(id);

2、修改路由配置。在从商品列表进入商品详情时不在传输商品名称,修改传输商品ID

3、注入ProductService并使用其服务。

 

 

添加一个服务:ng g service shared/product

 

修改product.service.ts

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

@Injectable()

export class ProductService {

//数组

private products:Product[]=[

new Product(1,"第一个商品",1.99,3.5,"我是学习Angular",["电子","物电"]),//ID 商品名称,价格,星级,商品描述,商品类别

new Product(2,"第二个商品",1.99,1.5,"我是学习Angular",["电子","物电"]),

new Product(3,"第三个商品",1.99,2.5,"我是学习Angular",["电子","物电"]),

new Product(4,"第四个商品",1.99,3.5,"我是学习Angular",["电子","物电"]),

new Product(5,"第五个商品",1.99,2.5,"我是学习Angular",["电子","物电"]),

new Product(6,"第六个商品",1.99,4.5,"我是学习Angular",["电子","物电"])

];

private comments:Comment[]=[//商品评论的实体,包括商品评论的信息

new Comment(1,1,"201842317:14:08","张三",3,"东西很好"),

new Comment(2,1,"201842317:14:08","李四",3,"东西挺好"),

new Comment(3,1,"201842317:14:08","王五",3,"东西还行"),

new Comment(4,1,"201842317:14:08","赵柳",3,"东西不错")

]

constructor() { }

//第一个方法,返回这个数组信息

getProducts():Product[]{

return this.products;

}

//根据商品的id,返回相应的商品

getProduct(id:number):Product {

return this.products.find((product)=>product.id==id);

}

//根据商品的id,返回所有的评论信息(filter:是过滤)

getCommentsForProdutId(id:number):Comment[]{

return this.comments.filter((comment:Comment)=>comment.productid==id);

}

}

export class Product{

constructor(

public id:number,

public title:string,

public price:number,

public rating:number,

public desc:string,

public categories:Array<string>

){}

}

//商品评论的类

export class Comment{

constructor(public id:number,

public productid:number,

public timestamp:string,

public user:string,

public rating:number,

public content:string

){

}

}

解释:主要就是将数据移植到这里来,Product,就是一个实体

修改路由配置:修改app.module.ts(之前传的是商品的名称,现在传的是id,所以修改两处

{第一处:path:'product/:productId',component:ProductDetailComponent}中的prodTitle改成productId  第二处:providers: [ProductService]

//-------------------------------------------------------------------------

部分代码:如下

import { ProductService } from './shared/product.service';

const routeConfig:Routes=[

{path:'',component:HomeComponent},

{path:'product/:productId',component:ProductDetailComponent}

]

 

修改商品组件的模板上:product.component.html

<!--let product of products绑定后台的数据-->

<div *ngFor="let product ofproducts" class="col-md-4 col-sm-4 col-lg-4">

<div class="thumbnail">

<!-- <img src="http://placehold.it/320X150">-->

<img[src]="imgUrl"><!--属性绑定 -->

<div class="caption">

<h4class="pull-right">{{product.price}}</h4>

<h4><a [routerLink]="['/product',product.id]">{{product.title}}</a></h4>

<p>{{product.desc}}</p>

</div>

<div>

<app-stars [rating]="product.rating"></app-stars>

<!-- <app-stars>{{product.rating}}</app-stars>-->

</div>

</div>

</div>

商品详情的组件上,修改控制器:product-detail.component.ts

 

export class ProductDetailComponentimplementsOnInit {

product:Product;

comments:Comment[];

constructor(private routeInfo:ActivatedRoute,

private productService:ProductService) { }

ngOnInit() {

let productId:number=this.routeInfo.snapshot.params["productId"]

//this.productTitle=this.routeInfo.snapshot.params["prodTitle"]

}

}

 

 

注入productService并且使用其服务:修改app.module.ts

providers: [ProductService],//把服务声明在模块的providers的属性中

 

 

然后在商品组件中构造函数中注入productService修改product.component.ts

constructor(private productService:ProductService) { }

详细代码:

import { Component, OnInit } from '@angular/core';

import { ProductService, Product } from '../shared/product.service';

@Component({

selector: 'app-product',

templateUrl: './product.component.html',

styleUrls: ['./product.component.css']

})

export class ProductComponent implements OnInit {

private products:Product[];

private imgUrl='http://placehold.it/320X150';

constructor(private productService:ProductService) { }

ngOnInit() {//组件实例化的钩子

this.products=this.productService.getProducts();

}

}

 

然后接着在修改product-detail.component.ts

this.product=this.productService.getProduct(productId);

 

然后接着修改product-detail.component.html

 

<div class="thumbnail">

<img src="http://placehold.it/820X230">

<h4 class="pull-right">{{product.price}}</h4>

<h4>{{product.title}}</h4>

<p>{{product.desc}}</p>

<div>

<p class="pull-right">{{comments.length}}</p>

<p>

<app-stars [rating]="product.rating"></app-stars>

</p>

</div>

</div>

<div class="well">

<div class="row" *ngFor="let comment ofcomments">

<hr>

<div class="col-md-12">

<app-stars [rating]="comment.rating"></app-stars>

<span>{{comment.user}}</span>

<span>{{comment.timestamp}}</span>

<p></p>

<p>{{comment.content}}</p>

</div>

</div>

</div>

相关文章
相关标签/搜索