服务和常规打字稿类之间的接口?

时间:2017-04-24 01:39:51

标签: angular typescript angular2-services

我有一个独特的情况,我发现自己很困惑。我有一个标准的typescript类(.ts)扩展,需要使用angular2服务中的方法。到目前为止,我无法找到实现这一目标的方法。

我会尽可能简单地尝试解释一下,因为我的代码库目前非常复杂。

有问题的服务是operation.service.ts

import { Injectable } from '@angular/core';
import { Http, Response, Headers } from '@angular/http';
import { Operation } from './operation';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';

@Injectable()
export class OperationService {

  private operationCatalogue: Operation[] = [];
  private url = './src/app/operation-catalogue/operations.json';

  constructor(private http:Http) {
    this.init();
  }

  init(){
      this.fetchOperations().subscribe(res => {
        var i;
        for(i in res["operations"]){
          this.operationCatalogue[i] = new Operation(res["operations"][i]["name"],
                                                     res["operations"][i]["description"],
                                                     res["operations"][i]["iconName"],
                                                     res["operations"][i]["inputs"],
                                                     res["operations"][i]["outputs"]
                                                 );
        }
      });
  }

  getOperations(){
    return this.operationCatalogue;
  }

  fetchOperations(): Observable<Operation[]>{
      return this.http.get(this.url).map(res => res.json());
  }

  /*
  Get a single operation from the operation catalogue.
  */
  getOperation(name: String): Operation {
    var theOne;
    for (var i = 0; i < this.operationCatalogue.length; i++){
        if (this.operationCatalogue[i].name === name){
            theOne = this.operationCatalogue[i];
        }
    }
    return theOne;
  }
}

您将从此代码中看到,该服务根据本地源Operation文件中的数据构建了这些.json个对象。在生产中,我的应用程序将从服务器而不是本地文件中获取数据。

要注意的重要方法是getOperation(),它接受​​一个字符串并从数组中返回一个Operation对象。

此服务是我的应用程序的关键部分,用于填充另一个组件中的HTML列表。

现在,我有另一个名为WSJSerializer的班级。简单地说,只是为了给你一些上下文,这个类接受一个JSON字符串,该字符串表示在磁盘上找到的操作对象数组,并将它们转换为Operation个对象。 要执行此操作,WSJSerializer需要使用getOperation()的{​​{1}}方法。

OperationService

WSJSerializer.ts

这是我的问题的症结所在。我无法与export class WSJDeserializer { private jsonString : string; private parsedString : Object; constructor(string : String){ this.jsonString = <string> string; this.parsedString = JSON.parse(this.jsonString); } public deserialize() { var rootOp = this.parsedString["operation"]; var childOps = rootOp["operations"]; var numOps = childOps.length; for (var i = 0; i < numOps; i++){ var childOp = childOps[i]["operation"]; this.deserializeObject(childOp); } } private deserializeObject(operation : Object){ //NEED TO USE THE getOperation() METHOD HERE!!!! } } 中的OperationService进行交互,我猜测它是某种角度限制。我尝试WSJSerializer import进入OperationService,然后调用WSJSerializer方法,但我收到以下错误:

getOperation()

如何在WSJDeserializer.ts (25,26): Property 'getOperations' does not exist on type 'typeof OperationService'.) 内拨打getOperation()的{​​{1}}方法? 如果不能直接使用,我可以吗?编写某种接口(不是OO概念接口)或辅助类来解决问题?还有其他一些解决方法吗?

其他信息:

  • OperationService用于我的应用程序的根角度组件,但WSJSerializer不是。
  • WSJSerializer用于根组件的子组件,根组件可通过OperationService直接访问该组件。
  • OperationService不是服务,因为它需要通过调用方法直接修改其他角度组件。

使用ViewChild()的根组件:

WSJSerializer

2 个答案:

答案 0 :(得分:2)

在当前状态WSJSerializer必须使用DI模式(而不是Angular DI)才能获得OperationService的实例:

export class WSJDeserializer {
    ...
    constructor(private operationService: OperationService, string : String){
        this.jsonString = <string> string;
        this.parsedString = JSON.parse(this.jsonString);
    }
    ...
    private deserializeObject(operation : Object){
        this.operationService.getOperation(...);
        ...
    }
}

应该从实例化此类的注入中传递,即组件:

new WSJDeserializer(workspaceString, this.operationService)

这看起来像是一个设计问题,正确的重构解决方案可能取决于问题中没有解释的其他因素。

一种可能性是错误的东西被视为班级的实体。是否真的需要一个保持状态(parsedString)的对象,并且能够多次反序列化它?如果没有,则序列化程序可以变为单例可注入,接受字符串作为其方法的参数:

@Injectable()
export class WSJDeserializer {
    constructor(private operationService: OperationService) {}

    deserialize(string : String) {
            ...
            this.deserializeObject(string , childOp);
            ...
    }

    private deserializeObject(string : String, operation : Object){
        this.operationService.getOperation(...);
        ...
    }
}

另一种可能性是实体是正确的,但实际上需要一个保持状态的实例,因此一个类是不够的。单身注射应该以任何方式存在以获得OperationService。所以应该有两个类而不是一个:

export class WSJDeserializable {
    ...
    constructor(string : String){
        this.jsonString = <string> string;
        this.parsedString = JSON.parse(this.jsonString);
    }
}

@Injectable()
export class WSJDeserializer {
    constructor(private operationService: OperationService) {}

    deserialize(deserializableObj: WSJDeserializable) {
            ...
            this.deserializeObject(deserializableObj, childOp);
            ...
    }
    ...
}

哪个应该从组件传递:

const deserializableObj = new WSJDeserializable(...);
deserializer.deserialize(deserializableObj);

有更多选项可以做到这一点,例如WSJDeserializer实例可以有工厂方法创建WSJDeserializable实例,但最后它保持单例,因为Angular服务是单例(在单个注入器中)。

答案 1 :(得分:0)

那么,您需要OperationService内的WSJSerializer个实例吗?只有一种方式可以做到这一点,那就是通过注入器。为了使WSJSerializer可注射,您必须将其转换为服务。

嗯,这有点谎言。还有另一种方式。如果您无法提供WSJSerializer服务,则还需要确保OperationService也不是服务。这很容易做到。您可以使用本机库(XmlHttpRequestfetch(请注意,fetch仅适用于现代浏览器),而不是使用角度Http服务。