Angular 2:如何在创建服务配置之前传递它?

时间:2016-12-25 20:26:48

标签: angular

我有一个典型的用例,我必须使用不同的端点websocket URL连接到不同的后端服务。

我在Angular 2中编写了通用服务,见下文:

import {Injectable} from "@angular/core";
import {Subject} from "rxjs/subject";
import {Observable} from "rxjs/observable";
import {WebSocketSubject, WebSocketSubjectConfig} from "rxjs/observable/dom/WebSocketSubject";
import {Observer} from "rxjs/observer";

@Injectable()
export class WebSocketService<T> extends Subject<T> {
    private reconnectionObservable: Observable<number>;
    private wsSubjectConfig: WebSocketSubjectConfig;
    private socket: WebSocketSubject<any>;
    private connectionObserver: Observer<boolean>;
    public connectionStatus: Observable<boolean>;


    constructor(private config: WebServiceConfig) {
        super();

        // connection status
        this.connectionStatus = new Observable((observer) => {
            this.connectionObserver = observer;
        }).share().distinctUntilChanged();

        // config for WebSocketSubject
        // except the url, here is closeObserver and openObserver to update connection status
        this.wsSubjectConfig = {
            url: config.URL,
            closeObserver: {
                next: (e:CloseEvent) => {
                    this.socket = null;
                    this.connectionObserver.next(false);
                }
            },
            openObserver: {
                next: (e:Event) => {
                    this.connectionObserver.next(true);
                }
            }
        };
        this.connect();
        // we follow the connection status and run the reconnect while losing the connection
        this.connectionStatus.subscribe((isConnected) => {
            if (!this.reconnectionObservable && typeof(isConnected) == "boolean" && !isConnected) {
                this.reconnect();
            }
        });
    }

    connect():void {
        this.socket = new WebSocketSubject(this.wsSubjectConfig);
        this.socket.subscribe(
            (m) => {
                this.next(m); // when receiving a message, we just send it to our Subject
            },
            (error:Event) => {
                if (!this.socket) {
                    // in case of an error with a loss of connection, we restore it
                    this.reconnect();
                }
            });
    }

    reconnect():void {
        this.reconnectionObservable = Observable.interval(this.config.getRetryInterval())
            .takeWhile((v, index) => {
                return index < this.config.attempts && !this.socket
            });
        this.reconnectionObservable.subscribe(
            () => {
                this.connect();
            },
            null,
            () => {
                // if the reconnection attempts are failed, then we call complete of our Subject and status
                this.reconnectionObservable = null;
                if (!this.socket) {
                    this.complete();
                    this.connectionObserver.complete();
                }
            });
    }

    send(data:any):void {
        this.socket.next(this.config.serializer(data));
    }
}

export enum TimeUnits {
    SECONDS = 1000,
    MINUTES = SECONDS * 60,
    HOURS = MINUTES * 60,
    DAYS = HOURS * 24
}

export class WebServiceConfig {
    URL: string = 'ws://localhost:4242/ws';
    attempts: number = 10; /// number of connection attempts
    retryUnit: TimeUnits = TimeUnits.SECONDS; /// pause between connections
    retryInterval: number = 5;

    serializer: (data: any) => any = function (data: any) {
        return JSON.stringify(data);
    };
    deserializer: (e: MessageEvent) => any = function (e: MessageEvent) {
        return e;
    };

    getRetryInterval(): number {
        return this.retryUnit * this.retryInterval;
    };
}

现在问题是如何创建具有不同配置的新实例?

我认为可以扩展到子类并传递configure的一种方法。是否有更好的方法而不是创建扩展类?

配置是动态的!我的意思是它将被写入服务器端的页面(我们在后端使用把手来渲染模板)。

2 个答案:

答案 0 :(得分:1)

有几种方法可以做你想做的事:

export class SampleConfig {

    constructor(public value:string)
    {
    }
}

@Injectable()
export class SampleService {

    constructor(config:SampleConfig)
    {
        console.debug('config', config);
    }
}

providers      : [
    ...
    {provide: SampleService, useFactory: () => new SampleService(new SampleConfig('1'))},
    ...
],

providers      : [
    ...
    {provide: SampleConfig, useValue: new SampleConfig('1')},
    SampleService,
    ...
],

答案 1 :(得分:0)

我的应用程序中有类似的要求,只需使用基本服务,效果很好。你对配置对象继承的反对意见是什么?这是我如何设置我的例子,这很方便......

export class BaseService {

  protected options: { ... };

  constructor(...) { }

  init(options) {
    this.options = options;
    ...
  }

然后你需要的任何子类都可以构建你的选项对象并用它们调用init。这样,您只需编写一次所有方法的抽象版本。我的基本服务非常丰富,但所有的儿童课程都非常简洁。