【问题标题】:What is the equivalent of a factory in Angular2?Angular2中的工厂相当于什么?
【发布时间】:2016-09-27 16:43:15
【问题描述】:

所以我习惯在 Angular 中使用工厂和服务。

我正在阅读 Angular2 文档,但没有看到任何相当于工厂的东西。 Angular2 的等价物是什么?

【问题讨论】:

    标签: angularjs angular


    【解决方案1】:

    工厂、服务、常量和值都在 Angular2 中消失了。 Angular2 与经典的 Angular 完全不同。在Angular2中,核心概念是

    • 组件
    • 依赖注入
    • 绑定

    服务、工厂、提供者和常量的想法在 Angular 1 中受到了批评。很难在两者之间做出选择。删除它们会简化一些事情。

    在最初的 Angular 中,你会定义一个这样的服务

    app.service('BookService', ['$http', '$q', BookService]);
    function BookService($http, $q){
      var self = this;
      var cachedBooks;
      self.getBooks = function(){
        if (cachedBooks) {
          return $q.when(cachedBooks);
        }
        return $http.get('/books').then(function(response){
          cachedBooks = response.data.books;
          return cachedBooks;
        })
      }
    }
    

    Angular2 极大地利用了 ES6 语法,使代码更具可读性和易于理解。

    ES6 中的一个新关键字是class,可以将其视为一种服务。

    ES6 类是基于原型的 OO 模式的简单糖。拥有一个方便的声明形式使类模式更易于使用,并鼓励互操作性。类支持基于原型的继承、超级调用、实例和静态方法以及构造函数。

    下面是相同代码在 Angular2 中的样子

    import {HttpService, Promise}  from '../Angular/Angular2';
    export class BookService{
        $http, $q, cachedBooks;
        constructor($http: HttpService, $q: Promise) {
            this.$http = $http;
            this.$q = $q
        }
        getBooks() {
        if (this.cachedBooks) {
            return this.$q.when(this.cachedBooks);
        }
        return this.$http.get('/books').then(function(data) {
            this.cachedBooks = data.books;
            return this.cachedBooks;
        })
      }
    }
    

    【讨论】:

    • 为什么你会说 services 在 Angular 2 中消失了?官方教程中作为一般概念还是大段的:angular.io/docs/ts/latest/tutorial/toh-pt4.html
    • 你能在答案中展示如何创建共享对象吗?
    • 继 @zoonman 之后,还需要类工厂来隐藏类的 DI 依赖关系,如下所示:angular.io/docs/ts/latest/guide/…
    • 我认为这不能回答最初的问题。即使“工厂”别名没有以角度实现,该模式仍然是可行的,并且与正常的服务模式有显着区别。
    • 我认为由于 es6 有一个 'class' 关键字,我们可以使用 class 来替换 factory。工厂很像一个班级
    【解决方案2】:

    感谢@Richard Hamilton 的回答,除此之外还有几点需要注意。

    对于工厂、服务等,在 Angular2 中我们有服务(或共享服务)。我们必须让我们的服务Injectable 才能使用它。

    注意:此代码属于 beta 版本,不是 RC。

    import {Component, Injectable,Input,Output,EventEmitter} from 'angular2/core'
    import {Router} from 'angular2/router';
    import {Http} from 'angular2/http';
    
    export interface ImyInterface {
       show:boolean;
    }
    
    @Injectable()      <---------------------------- Very Important
    export class sharedService {  <----------------- Service Name
      showhide:ImyInterface={show:true};
    
      constructor(http:Http;router:Router)
      {
        this.http=http;
      }     
      change(){
            this.showhide.show=!this.showhide.show;
      }
    } 
    

    如果我想在我的应用程序的任何地方使用,那么我必须像这样在引导函数中注入这个服务,

    bootstrap(App, [HTTP_PROVIDERS,sharedService    <--------Name Injection
          ROUTER_PROVIDERS,bind(APP_BASE_HREF).toValue(location.pathname)
    ]);
    

    这样,它会创建您的服务的单个实例。如果您不想使用单实例,您可以做的是 - 您可以在 @component 装饰器中使用 Providers:[sharedService] 元数据。

    然后,在您的组件之一中使用它,

    export class TheContent {
      constructor(private ss: sharedService) {  <--------Injection dependency of your newly created service
        console.log("content started");
      }
      showhide() {
        this.ss.change();  <----- usage
      }
    }
    

    Check working example here

    【讨论】:

    • bind(...).toXxx(...) 是不推荐使用的语法。改用provide(..., {useXxx: ...})
    • 感谢您的更新。我在写这些东西时没有注意到它。
    【解决方案3】:

    我不知道工厂在 Angular1 中究竟做了什么,但在 Angular2 中有 useFactory:

    { 
      provide: SomeClass, 
      useFactory: (dep1, dep2) => (x) => new SomeClassImpl(x, dep1, dep2),
      deps: [Dep1, Dep2]
    }
    

    如果默认值不符合您的需求,则提供您自己的实例构造逻辑。

    您也可以自己注入工厂来创建新实例:

    /* deprecated or removed depending on the Angular version you are using */
    provide(SomeClass, {
        useFactory: (dep1, dep2) => {
            (x) => new SomeClassImpl(x, dep1, dep2), 
        },
        deps: [Dep1, Dep2]
    })
    
    constructor(@Inject(SomeClass) someClassFactory: any) {
      let newSomeClass = someClassFactory(1);
    }
    

    参数 x 必须有类型赋值,否则 angular 不知道如何处理。

    class SomeClassImpl {
      constructor(x: number, dep1: Dep1, dep2: Dep2){}
    }
    

    【讨论】:

    • deps 属性是否应该与 useFactory 在同一范围内?
    • 据我所知,我用 Plunker 回答了一个类似的问题。在这里也是一个好主意:-/。再次感谢您的修复。
    • @GünterZöchbauer 看着let newSomeClass = someClassFactory(1);(中间剪断) - 在 CTOR 中,someClassFactory: any 已经(!)调用,已经返回 new SomeClassImpl。那么你为什么在let newSomeClass = someClassFactory(1); 中再次调用它呢?我错过了什么吗?
    • 感谢您的提示。注册提供程序的“新”语法的更新我忘记了(x) =&gt;。目的是注入工厂函数,而不是工厂函数的结果。
    【解决方案4】:

    如果您需要某个组件中的服务的新实例,您需要在该组件中提供它,如下所示:

    @Component({
      selector:    'hero-list',
      templateUrl: './hero-list.component.html',
      providers:  [ HeroService ]
    })
    

    这将像工厂一样生成HereService 的新实例。

    【讨论】:

      猜你喜欢
      • 2016-10-09
      • 2016-04-05
      • 1970-01-01
      • 2020-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-15
      • 2020-04-26
      相关资源
      最近更新 更多