如何在angular4+;服务

如何在angular4+;服务,angular,typescript,service,interface,getter-setter,Angular,Typescript,Service,Interface,Getter Setter,我有一些JavaScript和angular的经验,但我不能完全理解一些概念。 我正在尝试构建一个服务来存储一些设置,这些设置能够在发生更改时通知实现它的组件 设置为每个属性调用onChange函数的setter似乎是一种老式的方法,我让它工作起来了。但我不喜欢那种棱角分明的方式, 由于它使类膨胀,对于我要添加的每个属性,我需要实现新的get&set方法。 因此,我希望有一个接口,在每次将属性设置为新属性时调用onChange函数。但是我找不到这个的语法 import { Injectable}

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

设置为每个属性调用onChange函数的setter似乎是一种老式的方法,我让它工作起来了。但我不喜欢那种棱角分明的方式, 由于它使类膨胀,对于我要添加的每个属性,我需要实现新的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
  }
}
从'@angular/core'导入{Injectable};
从“rxjs/Observable”导入{Observable};
从'rxjs/Subject'导入{Subject};
@可注射()
导出类服务设置{
私有构造:布尔=假;
私人目标FPS:数量=30;
private _showFPS:boolean=true;
专用视距:数字=7000;
private _enableantialiasing:boolean=true;
private settingsChanged=新主题();
构造函数(){
如果(本条构造){
log('serviceSettings aready exists');
还这个
}
这是真的;
}
onChange(){
this.settingsChanged.next();
//在本地存储中保存设置
//将它们发送到api以存储在服务器端
console.log(“设置已更改”);
}
onChangeNotice():可观察{
返回此.settingsChanged.asObservable();
}
设置目标FPS(val:编号){
此参数为。_targetFPS=val
this.onChange()
}
获取targetFPS():编号{
将此返回。\u targetFPS
}
设置showFPS(val:boolean){
这个。_showFPS=val
this.onChange()
}
get showFPS():布尔值{
把这个还给我
}
设置enabelationalising(val:boolean){
这是._enabelationaliasing=val
this.onChange()
}
get enabelationaliasing():布尔值{
把这个还给我
}
设置视距(val:编号){
这是。_viewdance=val
this.onChange()
}
获取viewDistance():编号{
返回此值。\u viewDistance
}
}
在这个特定的上下文中,它是一个小游戏的设置服务——“引擎”,我正在使用THREE.js。如果要启用/禁用抗锯齿,但如果任何其他设置已更改,则需要恢复渲染器


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

我的方法是将所有变化放在一个对象中,这样我只需要一个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];}

这是基本的代码,很少检查,但你明白了。我首先要做的改进之一是使用枚举,这样在最后一段代码中,我就不会硬编码属性名。

我的方法是将所有更改放在一个对象中,这样我只需要一个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];}

这是基本的代码,很少检查,但你明白了。我首先要做的改进之一是使用枚举,这样在最后一段代码中,我就不会硬编码属性名了。

谢谢您的快速回答!唯一让人想到的是拳头玻璃,这个二传手不打字checking@MaDsaiboT你说得对。有几个问题。正如我写的,“这是基本代码,很少检查”这不是生产代码,而是一些东西,把你的方向,我会去。如果需要,您可以通过使用
映射
并在设置属性之前对其进行检查来轻松实现类型检查。@MaDsaiboT作为替代方法,您可以要求
changeState()
接受
StateInterface
对象(具有
state
属性的接口)。只需将界面中的所有属性设置为可选,并调整
changeState()
代码以读取提供的属性,并将值复制到本地
状态
属性。这将确保类型检查。它还有一个额外的好处,即允许您一次更改多个设置,同时只发出一个更改通知。这只是更复杂的代码,但这是我在自己的应用程序中所做的。再次感谢,我将尝试一下!您对可观察对象的重构也非常有用。有一点我不明白,在antiAliasingChanges$=this.settingsService.changeNotices$中,$是什么意思?“这是强制性的还是仅仅是一种惯例?”MaDsaiboT说,但这并没有什么特别之处,一些人当然选择不使用它。保持一致。谢谢你的快速回答!唯一让人想到的是拳头玻璃,这个二传手不打字checking@MaDsaiboT你说得对。有几个问题。正如我写的,“这是基本代码,很少检查”这不是生产代码,而是一些东西,把你的方向,我会去。如果需要,您可以通过使用
映射
并在设置属性之前对其进行检查来轻松实现类型检查。@MaDsaiboT作为替代方法,您可以要求
changeState()
接受
StateInterface
对象(具有
state
属性的接口)。只需将界面中的所有属性设置为可选,并调整
changeState()
代码以读取提供的属性,并将值复制到本地
状态
属性。这将确保类型检查。它还有一个额外的好处,即允许您一次更改多个设置,同时只发出一个更改通知