【问题标题】:How to build an interface for setters in a angular4+ service?如何为 angular4+ 服务中的设置器构建接口?
【发布时间】:2017-08-22 16:18:00
【问题描述】:

我有一些 JavaScript 和 Angular 方面的经验,但我无法完全理解一些概念。 我正在尝试构建一个服务来存储一些设置,这些设置能够通知实现它的组件发生了更改。

为每个属性设置调用 onChange 函数的设置器似乎是老式的方法,我得到了它的工作。但我不觉得有角度的方式, 因为它使类膨胀,并且对于我要添加的每个属性,我都需要实现新的 get & set 方法。 所以我想要一个接口,每次将属性设置为新的东西时调用 onChange 函数。但我找不到这个的语法。

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

@Injectable()
export class serviceSettings {
  private constructed: boolean = false;

  private _targetFPS:          number  = 30;
  private _showFPS:            boolean = true;
  private _viewDistance:       number  = 7000;
  private _enabelAntialiasing: boolean = true;

  private settingsChanged =   new Subject();

  constructor() {
    if (this.constructed) {
        console.log('serviceSettings aready exists');
        return this
    }
    this.constructed = true;
  }

  onChange() {
    this.settingsChanged.next();
    //save setting in local storage
    //send them to a api to store them server sided
    console.log('settings changed');
  }

  onChangeNotice():Observable<any> {
    return this.settingsChanged.asObservable();
  }

  set targetFPS(val:number) {
    this._targetFPS = val
    this.onChange()
  }

  get targetFPS():number{
    return this._targetFPS
  }

  set showFPS(val:boolean) {
    this._showFPS = val
    this.onChange()
  }

  get showFPS():boolean {
    return this._showFPS
  }

  set enabelAntialiasing(val:boolean) {
    this._enabelAntialiasing = val
    this.onChange()
  }

  get enabelAntialiasing():boolean {
    return this._enabelAntialiasing
  }

  set viewDistance(val:number) {
    this._viewDistance = val
    this.onChange()
  }

  get viewDistance():number{
    return this._viewDistance
  }
}

在这个特定的上下文中,它是我正在使用 THREE.js 开发的一个小游戏“引擎”的设置服务。如果我想启用/禁用抗锯齿,但如果任何其他设置已更改,则需要恢复渲染器。

TL:DR:我必须根据发生的变化对变化做出不同的反应。

【问题讨论】:

    标签: angular typescript service interface getter-setter


    【解决方案1】:

    我的方法是将所有更改放在一个对象中,这样我只需要一个 setter 和一个 getter。我还将标准化更改的发出方式,以便应用程序中关心不同更改的不同部分只获得他们需要的内容。

    一、换界面:

    export interface stateChange{
        propName:string,
        oldVal:any,
        newVal:any
    }
    

    接下来,设置服务:

    // Stores current settings
    private state = {
        fps:          30,
        showFPS:      true,
        antiAliasing: false,
        viewDistance: 7000
    };
    
    public settings = new Subject();
    
    // Notifier is shared across all subscribers
    // Notice this is not a function that returns, but the Observable itself
    // (sharing needs the same Observable object, not a new one created on each func call)
    public changeNotices$:Observable<stateChange> = this.settings.asObservable().share();
    
    changeState(prop:string,val:any){
        let oldVal = this.state[prop];
        if(oldVal == val) return; // no change
        this.state[prop] = val; // save new state
        this.settings.next( // emit state change notice
            {propName:prop, oldVal:oldVal, newVal:val}
        );
    }
    
    getState(prop:string){return this.state[prop];}
    

    如果我只关心抗锯齿,以下是我使用服务的方式:

    antiAliasingChanges$ = this.settingsService.changeNotices$
        .filter((e:stateChange) => e.propName == 'antiAliasing')
        .subscribe((e:stateChange) => {
            if(e.newVal === true) console.log('antiAliasing is ON');
        });
    

    这是基本代码,几乎没有检查,但你明白了。我首先要做的改进之一是使用枚举,因此在最后一段代码中,我不会对属性名称进行硬编码。

    【讨论】:

    • 感谢您的快速答复!第一眼想到的唯一问题是这个 setter 没有类型检查
    • @MaDsaiboT 你是对的。有几个问题。正如我所写,“这是基本代码,几乎没有检查”这不是生产代码,而是让你朝着我要去的方向前进的东西。如果需要,您可以轻松实现类型检查,方法是使用 Map&lt;propName, typeName&gt; 并在设置属性之前对其进行检查。
    • @MaDsaiboT 作为替代方案,您可以要求changeState() 接受StateInterface 对象(具有state 属性的接口)。只需在界面中将所有属性设为可选,并调整changeState() 代码以读取提供的属性并将值复制到本地state 属性。这将确保类型检查。它的另一个好处是允许您一次更改多个设置,同时只发出一个更改通知。这只是更复杂的代码,但这是我在自己的应用程序中所做的
    • 再次感谢我会试一试!您对 observable 的重构也非常有帮助。只是一件小事我不明白 antiAliasingChanges$ = this.settingsService.changeNotices$ 中 $ 的含义是什么?这是强制性的还是只是约定俗成的事情?
    • @MaDsaiboT it's a convention 但它没有什么特别之处,有些人当然选择不使用它。保持一致即可。
    猜你喜欢
    • 2015-12-19
    • 2016-03-14
    • 1970-01-01
    • 2013-05-09
    • 2023-04-02
    • 2021-02-09
    • 2018-08-15
    • 2014-07-03
    • 1970-01-01
    相关资源
    最近更新 更多