如何在 angular4+ 服务中为 setter 构建接口?
How to build an interface for setters in a angular4+ service?
我对 JavaScript 和 angular 有一些经验,但我不太了解某些概念。
我正在尝试构建一个服务来存储一些设置,这些设置能够通知实现它的组件发生了更改。
设置为每个 属性 调用 onChange 函数的设置器似乎是老式的方法,我让它工作了。但我不喜欢 angular 方式,
因为它使 class 膨胀,对于我想添加的每个 属性,我需要实现新的获取和设置方法。
所以我想有一个接口,每次 属性 被设置为新的东西时调用 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
}
}
在这个特定的上下文中,它是一个小游戏的设置服务-"engine" 我正在使用 THREE.js。如果我想 enable/disable 抗锯齿,它需要恢复渲染器,但如果任何其他设置已更改则不需要。
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];}
如果我只关心抗锯齿,我将如何使用该服务:
antiAliasingChanges$ = this.settingsService.changeNotices$
.filter((e:stateChange) => e.propName == 'antiAliasing')
.subscribe((e:stateChange) => {
if(e.newVal === true) console.log('antiAliasing is ON');
});
这是基本代码,几乎没有检查,但您明白了。我要做的第一个改进是使用枚举,这样在最后一段代码中,我就不会硬编码 属性 名称。
我对 JavaScript 和 angular 有一些经验,但我不太了解某些概念。 我正在尝试构建一个服务来存储一些设置,这些设置能够通知实现它的组件发生了更改。
设置为每个 属性 调用 onChange 函数的设置器似乎是老式的方法,我让它工作了。但我不喜欢 angular 方式, 因为它使 class 膨胀,对于我想添加的每个 属性,我需要实现新的获取和设置方法。 所以我想有一个接口,每次 属性 被设置为新的东西时调用 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
}
}
在这个特定的上下文中,它是一个小游戏的设置服务-"engine" 我正在使用 THREE.js。如果我想 enable/disable 抗锯齿,它需要恢复渲染器,但如果任何其他设置已更改则不需要。
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];}
如果我只关心抗锯齿,我将如何使用该服务:
antiAliasingChanges$ = this.settingsService.changeNotices$
.filter((e:stateChange) => e.propName == 'antiAliasing')
.subscribe((e:stateChange) => {
if(e.newVal === true) console.log('antiAliasing is ON');
});
这是基本代码,几乎没有检查,但您明白了。我要做的第一个改进是使用枚举,这样在最后一段代码中,我就不会硬编码 属性 名称。