基于Angular4模块的服务与全局服务

时间:2017-07-13 22:39:18

标签: angular architecture angular2-services

我们目前正在开发一个Angular4应用程序并寻找有关服务架构的反馈。

该应用的五个“模块”是:

  • 一个
  • 2
  • 3
  • 4
  • 5

目前我们有一个特定于one的数据服务,但是,抽象类ApiService可以在其他四个模块中导入(参见下面的代码)。

以下是我正在思考的一些选项:

选项1: 将抽象类ApiService移动到我们的共享文件夹模块中,即共享文件夹模块将导入到五个模块中的每个模块中。

然后创建一个特定于每个模块的服务,该服务继承自ApiService。这样可以轻松管理每项服务。

选项2: 将抽象类移动到我们的共享文件夹中,并创建一个全局服务,其中包含所有五个模块的所有api调用。这样我们就可以使用单一服务来管理所有API连接。但是,该文件可能会变得有点大,难以管理。关于组织的想法?

选项3: 将可观察的服务一起废弃,并使用像ngrx / store这样的东西来处理状态。

我正在寻找有关数据服务架构的反馈。

模块酮数据service.ts

import { Injectable } from '@angular/core';
import { Http, Response, Headers, RequestOptions } from '@angular/http';

import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/map';

import { IPosition } from './position.model';
import { IPositionReference } from '../shared/side-pane/position-reference.model';
import { Subject } from 'rxjs/Subject';


export abstract class ApiService {
  protected BASE_URL = 'http://justtheurl.com';
  protected baseAndModuleUrl: string;

  private OPTIONS = new RequestOptions({
      headers: new Headers({
        'Authorization' : 'Basic thisIsJustForTesting'
      }),
      withCredentials: true
  });

  constructor(private http: Http, private module: string) {
    this.baseAndModuleUrl = `${this.BASE_URL}${module}`;
  }

  public getBaseModuleUrl() { return this.baseAndModuleUrl; }

  protected fetch(apiAction: string): Observable<any> {
    return this.http
      .get(`${this.baseAndModuleUrl}${apiAction}`, this.OPTIONS)
      .map((res: Response) => res.json().data);
  }

  protected post(apiAction: string, positions: Object[]): Observable<any> {
    return this.http
      .post(`${this.baseAndModuleUrl}${apiAction}`, positions, this.OPTIONS)
      .map((res: Response) => res.json());
  }

  protected upload(apiAction: string, file: FormData): Observable<any> {
    return this.http
      .post(`${this.baseAndModuleUrl}${apiAction}`, file, this.OPTIONS)
      .map((res: Response) => res.json());
  }

}

@Injectable()
export class ModuleOneDataService extends ApiService {
  public editableValues = new Subject<any>();

  constructor(http: Http) { super(http, '/api/module/one'); }

  public fetchTree(): Observable<IPosition[]> { return this.fetch('/tree'); }

  public fetchList(): Observable<IPosition[]> { return this.fetch('/list'); }

  public fetchIndividual(id: string): Observable<IPositionReference> { return this.fetch(`/node/${id}`); }

  public savePositionsToSubgraph(positions: Object[]): Observable<any> { return this.post('/subgraph/upsert', positions); }

  public mergeSubraphToMaster(): Observable<Object> { return this.post('/subgraph/merge', [{}]); }


}

1 个答案:

答案 0 :(得分:1)

ApiService可能根本不应该是抽象的。查看您发布的内容,它实际上充当了管理Angular HTTP服务的包装器。经常需要包装角度HTTP服务,因为它具有如此糟糕的API。

需要访问包装的HTTP工具的服务类应该注入此API服务而不是继承它。

这样做的原因是它们不是基类的逻辑后代,并且仅仅为了代码共享而使用继承会导致令人困惑的代码库。有更好的方法。

以下是我推荐的内容

应用/模块酮/数据service.ts

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

import ApiServiceFactory, {ApiService} from 'app/shared/api';

@Injectable() export class DataService {
  constructor(apiServiceFactory: ApiServiceFactory) {
    this.api = apiServiceFactory.create('/api/module/one');
  }

  api: ApiService;

  fetchTree(): Observable<IPosition[]> { 
    return this.api.fetch('/tree');
  }

  fetchList(): Observable<IPosition[]> {
    return this.api.fetch('/list');
  }

  fetchIndividual(id: string): Observable<IPositionReference> {
    return this.api.fetch(`/node/${id}`);
  }
}

应用/共享/ api.ts

import {Injectable} from '@angular/core';
import {Http} from '@angular/http';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/map';

@Injectable() export default class ApiServiceFactory {
  constructor(readonly http: Http) {}

  create(moduleApiSubpath: string): ApiService {
    return new ApiServiceImplementation(this.http, moduleApiSubpath);
  }
}

export interface ApiService {
  fetch(url): Observable<{}>;

  post(url:string, body: {}): Observable<{}>;

  // etc.
}

const baseUrl = 'http://justtheurl.com';

// there's actually no need to make this a class at all.
// It could be as simple as a function that returns an object literal.
// It doesn't matter much since it's not exported.
class ApiServiceImplementation implements ApiService {
  constructor(readonly http: Http, readonly moduleApiSubpath: string){}

  get baseModuleUrl() {
    return `${baseUrl}${this.moduleApiSubpath}`;
  }

  fetch(apiAction: string): Observable<{}> {
    return this.http
      .get(`${this.baseModuleUrl}${apiAction}`, this.options)
      .map(res => res.json().data);
  }

  // etc.
}

使用这种方法,唯一的共享注射剂将是ApiServiceFactory。您可以在共享模块中提供它,也可以在每个具有注入它的服务的模块中独立提供它。您不必担心额外的实例或类似的任何事情,因为该服务是无状态的,并且工厂返回的实际对象实际上是瞬态的。

请注意,如果角度为此模式提供了内置支持,因为传递注入相当普遍,并且有很多用例。虽然目前可以在组件级别上实现瞬态瞬态依赖注入行为,但如果不创建这样的工厂,就无法在服务级别上实现。

相比之下,像Aurelia这样的框架允许使用简单的@transient来装饰服务,而消费者则以类似的简单方式明确请求新实例。