我们目前正在开发一个Angular4应用程序并寻找有关服务架构的反馈。
该应用的五个“模块”是:
目前我们有一个特定于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', [{}]); }
}
答案 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
来装饰服务,而消费者则以类似的简单方式明确请求新实例。