Angular 角度8-服务注入和工厂模式
我简要地阅读了几篇文章和官方指南,但它们似乎不能帮助我解决我的任务。这就是我想要和做的 假设我有一个带有产品列表页面的Angular应用程序。此外,该应用程序将有类别列表页面和一些N个列表页面在未来。正如您所看到的,它们非常相似,在公共数据表中有一个组件Angular 角度8-服务注入和工厂模式,angular,typescript,dependency-injection,factory-pattern,Angular,Typescript,Dependency Injection,Factory Pattern,我简要地阅读了几篇文章和官方指南,但它们似乎不能帮助我解决我的任务。这就是我想要和做的 假设我有一个带有产品列表页面的Angular应用程序。此外,该应用程序将有类别列表页面和一些N个列表页面在未来。正如您所看到的,它们非常相似,在公共数据表中有一个组件 <app-data-table [type]="'product'"></app-data-table> 所以,正如您可能已经猜到的,我的意思是使这个组件服务类型不可知。这就是我创建并注入数据工厂的原因: import
<app-data-table [type]="'product'"></app-data-table>
所以,正如您可能已经猜到的,我的意思是使这个组件服务类型不可知。这就是我创建并注入数据工厂的原因:
import { Injectable } from '@angular/core';
import {ProductService} from "./product.service";
import {CategoryService} from "./category.service";
import {DataService} from "./data.service";
@Injectable({
providedIn: 'root'
})
export class DataFactoryService {
private serviceTokenMapping = {
"product": ProductService,
"category": CategoryService
};
constructor() { }
public getServiceBy(token: string): DataService {
return new this.serviceTokenMapping[token];
}
}
最后,我们为产品和类别提供了两项服务,并提供了一些简单的基本抽象类:
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export abstract class DataService {
abstract selectAll(): any[];
}
import { Injectable } from '@angular/core';
import {DataService} from "./data.service";
import {Product} from "./product";
@Injectable({
providedIn: 'root'
})
export class ProductService implements DataService {
constructor() {}
public selectAll(): Product[] {
console.log(`ProductService...`);
return [];
}
}
import { Injectable } from '@angular/core';
import {DataService} from "./data.service";
import {Category} from "./category";
@Injectable({
providedIn: 'root'
})
export class CategoryService implements DataService {
constructor() {}
public selectAll(): Category[] {
console.log(`CategoryService...`);
return [];
}
}
有趣的是,这个实现完全按照预期工作。所以我将表的类型作为product传递给product相关页面,category类型作为category等
问题是从角度(提供者、DI等)来看,我是否做了一些不正确的事情?我们是否有任何方法来实现这样一个要求,使其更加角度化?我认为每次触发
this.dataFactory.getServiceBy(this.type)时,您实际上都在实例化ProductService
和CategoryService
,而不是在Angular中实际使用依赖项注入
您可以使用@NgModule
的providers
属性指定每个依赖项的令牌,并使用@Inject
或injector.get获取依赖项
export interface DataService {
selectAll(): any[];
}
@Injectable({
providedIn: 'root'
})
export class ProductService implements DataService {
public static TOKEN = new InjectionToken<DataService>('ProductService_TOKEN');
constructor() {}
public selectAll(): Product[] {
console.log(`ProductService...`);
return [];
}
}
@Injectable({
providedIn: 'root'
})
export class CategoryService implements DataService {
public static TOKEN = new InjectionToken<DataService>('CategoryService_TOKEN');
constructor() {}
public selectAll(): Category[] {
console.log(`CategoryService...`);
return [];
}
}
@NgModule({
providers: [
{
provide: ProductService.TOKEN,
useExisting: forwardRef(() => ProductService),
multi: false
},
{
provide: CategoryService.TOKEN,
useExisting: forwardRef(() => CategoryService),
multi: false
}
]
})
export class YourModule {}
@Component({
selector: 'app-data-table',
templateUrl: './data-table.component.html',
styleUrls: ['./data-table.component.css']
})
export class DataTableComponent implements OnInit {
@Input() type: string;
private data: any[];
constructor(
@Inject(ProductService.TOKEN) private dataService: DataService,
private injector: Injector
) { }
ngOnInit(): void {
this.dataService.selectAll();
this.injector.get<DataService>(CategoryService.TOKEN).selectAll();
}
}
导出接口数据服务{
selectAll():任意[];
}
@注射的({
providedIn:'根'
})
导出类ProductService实现数据服务{
公共静态令牌=新注入令牌(“ProductService_令牌”);
构造函数(){}
public selectAll():产品[]{
log(`ProductService…`);
返回[];
}
}
@注射的({
providedIn:'根'
})
导出类CategoryService实现数据服务{
公共静态令牌=新注入令牌(“CategoryService_令牌”);
构造函数(){}
public selectAll():类别[]{
log(`CategoryService…`);
返回[];
}
}
@NGD模块({
供应商:[
{
提供:ProductService.TOKEN,
useExisting:forwardRef(()=>ProductService),
多重:假
},
{
提供:CategoryService.TOKEN,
useExisting:forwardRef(()=>CategoryService),
多重:假
}
]
})
导出类模块{}
@组成部分({
选择器:“应用程序数据表”,
templateUrl:'./data table.component.html',
样式URL:['./数据表.component.css']
})
导出类DataTableComponent实现OnInit{
@Input()类型:string;
私人数据:任何[];
建造师(
@注入(ProductService.TOKEN)私有数据服务:数据服务,
专用注射器:注射器
) { }
ngOnInit():void{
this.dataService.selectAll();
this.injector.get(CategoryService.TOKEN).selectAll();
}
}
我认为每次触发this.dataFactory.getServiceBy(this.type)
时,您实际上都在实例化ProductService
和CategoryService
,而不是在Angular中实际使用依赖项注入
您可以使用@NgModule
的providers
属性指定每个依赖项的令牌,并使用@Inject
或injector.get获取依赖项
export interface DataService {
selectAll(): any[];
}
@Injectable({
providedIn: 'root'
})
export class ProductService implements DataService {
public static TOKEN = new InjectionToken<DataService>('ProductService_TOKEN');
constructor() {}
public selectAll(): Product[] {
console.log(`ProductService...`);
return [];
}
}
@Injectable({
providedIn: 'root'
})
export class CategoryService implements DataService {
public static TOKEN = new InjectionToken<DataService>('CategoryService_TOKEN');
constructor() {}
public selectAll(): Category[] {
console.log(`CategoryService...`);
return [];
}
}
@NgModule({
providers: [
{
provide: ProductService.TOKEN,
useExisting: forwardRef(() => ProductService),
multi: false
},
{
provide: CategoryService.TOKEN,
useExisting: forwardRef(() => CategoryService),
multi: false
}
]
})
export class YourModule {}
@Component({
selector: 'app-data-table',
templateUrl: './data-table.component.html',
styleUrls: ['./data-table.component.css']
})
export class DataTableComponent implements OnInit {
@Input() type: string;
private data: any[];
constructor(
@Inject(ProductService.TOKEN) private dataService: DataService,
private injector: Injector
) { }
ngOnInit(): void {
this.dataService.selectAll();
this.injector.get<DataService>(CategoryService.TOKEN).selectAll();
}
}
导出接口数据服务{
selectAll():任意[];
}
@注射的({
providedIn:'根'
})
导出类ProductService实现数据服务{
公共静态令牌=新注入令牌(“ProductService_令牌”);
构造函数(){}
public selectAll():产品[]{
log(`ProductService…`);
返回[];
}
}
@注射的({
providedIn:'根'
})
导出类CategoryService实现数据服务{
公共静态令牌=新注入令牌(“CategoryService_令牌”);
构造函数(){}
public selectAll():类别[]{
log(`CategoryService…`);
返回[];
}
}
@NGD模块({
供应商:[
{
提供:ProductService.TOKEN,
useExisting:forwardRef(()=>ProductService),
多重:假
},
{
提供:CategoryService.TOKEN,
useExisting:forwardRef(()=>CategoryService),
多重:假
}
]
})
导出类模块{}
@组成部分({
选择器:“应用程序数据表”,
templateUrl:'./data table.component.html',
样式URL:['./数据表.component.css']
})
导出类DataTableComponent实现OnInit{
@Input()类型:string;
私人数据:任何[];
建造师(
@注入(ProductService.TOKEN)私有数据服务:数据服务,
专用注射器:注射器
) { }
ngOnInit():void{
this.dataService.selectAll();
this.injector.get(CategoryService.TOKEN).selectAll();
}
}
您应该仔细检查是否可以删除DataServiceFactory类并直接注入所需的服务。您还应该扩展抽象类(extends
而不是implements
)@ChristophLütjen感谢您的及时回复!你能举一些你建议的例子吗?如果我正在创建组件(new DataTableComponent(new ProductService()),我可以将服务注入组件,但它是由Angular injector创建的。我们使用指令解决了相同的问题。这里有一个选择器,如data table[products]
,您可以将数据表注入指令(并从那里设置dataTable.data)。我们这样做是为了解决“依赖于所有可用数据提供程序”的问题。您应该仔细检查是否可以删除DataServiceFactory类并直接注入所需的服务。此外,您还应该扩展抽象类(扩展
,而不是实现
)@ChristophLütjen感谢您的及时回复!您能给出一些您建议的示例吗?如果我正在创建组件(new DataTableComponent(new ProductService()),我可以将服务注入组件,但它是在