【问题标题】:How to use factory provider?如何使用工厂供应商?
【发布时间】:2017-02-09 18:16:15
【问题描述】:

我需要将一个服务注入到 Angular 2 应用程序中的另一个服务中。

阅读我推断的文档后,最好的方法是使用Factory Provider。但是,出现了两个问题:

1) 文档建议使用两个“代码段”创建 HeroServiceProvider 类:

let heroServiceFactory = (logger: Logger, userService: UserService) => {
  return new HeroService(logger, userService.user.isAuthorized);
};

export let heroServiceProvider =
  { provide: HeroService,
    useFactory: heroServiceFactory,
    deps: [Logger, UserService]
  };

我的问题是这个类一般应该是什么样子?应该在哪里添加上面的代码段?

2) 应该/如何使用这个工厂?我明白了,它应该被导入为:

import { heroServiceProvider } from './hero.service.provider';

@Component({
  selector: 'my-selector',
  template: `
  `,
  providers: [heroServiceProvider]
})

然后如何检索和访问所需的参数化服务?

【问题讨论】:

    标签: angular typescript dependency-injection


    【解决方案1】:

    问题 1:
    班级一般应该是什么样子?应该在哪里添加上面的代码段?

    答案:
    您可以创建一个文件来包含 hero 服务提供者及其工厂函数的代码。这个文件可以命名为hero.service.provider.ts
    并且,在另一个名为 hero.service.ts 的文件中编写 hero 服务的代码。

    查看这篇关于 how to use Angular Service Providers 的文章以查看更多示例。

    hero.service.provider.ts文件:

    import { HeroService } from './hero.service';
    import { Logger } from './logger.service';
    import { UserService } from './user.service';
    
    let heroServiceFactory = (logger: Logger, userService: UserService) => {
      return new HeroService(logger, userService.user.isAuthorized);
    };
    
    export let heroServiceProvider =
      { provide: HeroService,
        useFactory: heroServiceFactory,
        deps: [Logger, UserService]
      };
    

    问题 2: 应该/如何使用这个工厂?

    答案:
    按照您提供的示例代码,可以使用 @Component 装饰器中的 providers 字段和 service can be injected 通过类构造函数或使用 Angular 注入器对象为服务配置工厂。

    但是,当工厂供应商以这种方式配置时,摇树摇晃不起作用。如果您需要摇树工作,请查看此Angular tree shakable service example

    import { heroServiceProvider } from './hero.service.provider';
    import { HeroService } from './hero.service';
    
    @Component({
      selector: 'my-selector',
      template: ``,
      providers: [heroServiceProvider]
    })
    export class HeroComponent {
      constructor(private heroService: HeroService) { } 
    }
    

    【讨论】:

    • 非常感谢!我从您的博客中阅读了一些文章,并且发现了一些有趣的东西。我不知道您可以使用@Injectable({ providedIn: 'root', useFactory: () => {}, deps:[] }) 来在运行时做出决策并获得可摇树的依赖关系。太酷了!
    • OP 在其问题的开头说:“我需要将服务注入另一个服务”,此示例是关于将其注入组件,而不是服务。你知道如何实现这种行为吗?
    • @weilah 是的,这是对第一个问题的答复。阅读 OP 说“在阅读了我推断的文档后,最好的方法是使用工厂提供程序。但是,出现了两个问题:”这意味着工厂提供程序是这样做的方法。
    【解决方案2】:

    我没有足够的分数来评论 @mgmg 的回答,但这里有一些有用的信息......

    我在自己的应用程序中使用了文档(以及此问题的主题)中给出的提供者工厂模式,但在编译时不断出错

    错误中的错误遇到静态解析符号值。 不支持函数调用。考虑更换功能或 引用导出函数的 lambda...

    本质上,当在根模块中使用工厂依赖项时,必须提供它的所有依赖项。

    这意味着@mgmg的答案中给出的代码块应该严格具有依赖服务

    import { heroServiceProvider } from './hero.service.provider';
    import { UserService } from './user.service';
    import { Logger }      from './logger.service';
    
    ...
    
    @NgModule({
    
      ...
    
      providers: [
        Logger,
        UserService,
        heroServiceProvider
        // Wrapper for:
        //{ provide: HeroService,
        //  useFactory: (logger: Logger, userService: UserService) => {
        //    return new HeroService(logger, userService.user.isAuthorized)
        //  },
        //  deps: [Logger, UserService]
        //};
    
      ],
      bootstrap: [ AppComponent ]
    })
    

    注意,在角度文档here 中,heroServiceProvider 是在 heroes.component 中提供的,而不是在 app.module 中,并且对那里不需要 Logger 和 UserService。我认为这两个依赖项是从注入器树的更高层获取的。

    【讨论】:

    • 我同意:我得到了同样的错误:“错误中遇到解析符号....”我找到了解决方案:useFactory: (heroServiceFactory)。只需在工厂周围添加 ()。
    【解决方案3】:

    我在 app_initalizer 上注入了同样的问题,经过长时间的搜索,我找到了下面的解决方案。可能这对您的方案有帮助。

    @NgModule({
      imports: [ BrowserModule],
      ...
      providers: [
        {
          provide: HeroService,
          useFactory: heroServiceFactory,
          deps: [Logger, UserService],
          multi: true
        }
        ]
    })
    export class AppModule {}
    
    
    export function heroServiceFactory = (logger: Logger, userService: UserService) => {
        return new HeroService(logger, userService.user.isAuthorized);
    };
    

    【讨论】:

      【解决方案4】:

      1)您问题的第一部分很简单:您只需将提供的 sn-p 保存在单独的文件中,然后将其导入组件中,如您的问题所示:

      import { heroServiceProvider } from './hero.service.provider';

      2) 至于实际使用,其实不需要在组件中修改服务相关的代码。如果注入了原始服务,请继续使用它。您甚至不需要修改组件构造函数。服务提供者的想法是,您可以通过为每个组件提供自定义服务提供者来在每个组件的基础上自定义服务,并且您可以在工厂函数中进行特定于组件的初始化。只是不要忘记在组件的装饰器中列出您的服务提供者,Angular 会“自动”处理其余部分。

      【讨论】:

        【解决方案5】:

        今天我遇到了同样的问题并找到了一些解决方案。

        1) 我在 angular.io 中找到了确切的代码,请参见以下内容: https://github.com/angular/angular.io/blob/master/public/docs/_examples/dependency-injection/ts/src/app/heroes/hero.service.provider.ts(链接更新于 2017 年 3 月 15 日)。
        从这段代码来看, heroServiceProvider 不需要是一个类。

        2) 在 app.module.ts 中,@NgModule 中有 providers 属性。你可以像下面这样添加 heroServiceProvider:

        import { heroServiceProvider } from './hero.service.provider';
        
        ...
        
        @NgModule({
        
          ...
        
          providers: [
            heroServiceProvider
          ],
          bootstrap: [ AppComponent ]
        })
        

        通过像这样在@NgModule 中提供服务,您可以在应用程序范围内使用该服务。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-07-01
          • 1970-01-01
          • 2010-12-23
          • 2014-12-13
          • 2021-07-17
          • 2013-10-15
          • 2017-02-18
          • 1970-01-01
          相关资源
          最近更新 更多