我有一个统计应用程序。在我的页面的左侧,我有主题列表,在顶部 - 组列表。主要部分包含与主题和组相关的统计项目。
此外,我还有几个服务为我的应用程序提供业务逻辑。为简单起见,我们先谈谈其中三个: ThemeSerivce,GroupService 和 StatisticsService 。
最终用户可以操作主题和组列表(添加或删除项目),并且每次更改后都必须重新计算统计信息。在此应用程序中,我使用 rx.js 中的 Subjects 和 Subsription 来跟踪此类更改。
所以,在我的组件中,我可以这样写:
GroupComponent 的
removeGroup() {
this.groupService.removeGroup(this.group);
this.statisticsService.updateStatistics();
}
for ThemeComponent
removeTheme() {
this.themeService.removeTheme(this.theme);
this.statisticsService.updateStatistics();
}
但从逻辑上讲,这些组件不必了解统计数据。当然,我可以将 StatisticsService 的依赖关系移动到 ThemeService 和 GroupService ,但是我必须调用 statisticsService.updateStatistics()< / em>在每个更改主题或组集合的方法中。这就是我希望通过订阅实现直接跨服务通信的原因。
最后我的问题:
这根本不是一个好主意吗?
如果没问题,实施它的最佳方法是什么? 当我在组件中使用订阅时,我在 ngOnInit()方法中注册它并取消订阅 ngOnDestroy()以防止内存泄漏。 我可以在服务的构造函数中订阅吗?我何时何地取消订阅?或者,当我在App模块级别注册我的服务作为提供者时,它可能没有必要吗?
答案 0 :(得分:0)
StatisticsService
应订阅主题和群组列表。您的个人组件应仅订阅其各自的服务(ThemeComponent to ThemeService,Group to Group etc)。
为简单起见,我只关注ThemeService
,但GroupService
类似。调用remove时,ThemeService
应该有一个内部Subject
,Subject
下一个值(可能是整个新列表)。
StatisticsService
将订阅ThemeService
观察点并在更改后重新计算。它看起来像这样
/* theme.service.ts */
@Injectable()
export class ThemeService {
private _list$ = new Subject<ThemeList>();
get list(): Observable<ThemeList> {
return this._list$.asObservable();
}
set list(newList: ThemeList) {
this._list$.next(newList);
}
}
/* statistics.service.ts */
@Injectable()
export class StatisticsService {
private _calculation$ = new Subject<StatisticResult>();
constructor(private themeService: ThemeService) {
themeService.list.subscribe((themeList: ThemeList) => this.updateCalculation(themeList));
}
get calculation(): Observable<StatisticResult> {
return this._calculation$.asObservable();
}
updateCalculation(newData: ThemeList | GroupList) {
// ... do stuff
this._calculation.next(statisticResult);
}
}
/* statistics.component.ts */
@Component({
selector: 'statistics',
template: '<p>{{ statisticResult$ | async }}</p>'
})
export class StatisticsComponent {
statisticResult$: Observable<StatisticResult>;
constructor(private statisticsService: StatisticsService) {
this.statisticResult$ = statisticsService.calculation;
}
}