Angular跨服通信
Angular cross-service communication
我有一个统计应用程序。在我页面的左侧,我有主题列表,在顶部 - 组列表。主要部分包含与主题和组相关的统计项。
我还有几个服务可以为我的应用程序提供业务逻辑。为简单起见,让我们谈谈其中三个:ThemeSerivce、GroupService 和 StatisticsService.
最终用户可以操作主题和组列表(添加或删除项目),每次更改后我都必须重新计算统计信息。在此应用程序中,我使用 Subjects 和 Subsription 来自 rx.js 来跟踪此类更改.
所以,在我的组件中我可以这样写:
对于 GroupComponent
removeGroup() {
this.groupService.removeGroup(this.group);
this.statisticsService.updateStatistics();
}
对于 ThemeComponent
removeTheme() {
this.themeService.removeTheme(this.theme);
this.statisticsService.updateStatistics();
}
但从逻辑上讲,这些组件不必了解统计信息。当然,我可以将 StatisticsService 的依赖项移动到 ThemeService 和 GroupService 中,但之后我将不得不调用statisticsService.updateStatistics() 在每个改变主题或组集合的方法中。这就是为什么我想通过订阅实现直接的跨服务通信。
最后是我的问题:
这是个好主意吗?
如果可以的话,最好的实现方式是什么?
当我在组件中使用 Subscription 时,我在 ngOnInit() 方法中注册它并在 ngOnDestroy()[=50= 中取消订阅] 以防止内存泄漏。
我可以在服务的构造函数中订阅它吗?我应该何时何地退订?或者当我在 App 模块级别将我的服务注册为提供商时,也许没有必要?
StatisticsService
应订阅主题和组列表。您的各个组件应该只订阅它们各自的服务(ThemeComponent 到 ThemeService,Group 到 Group 等)。
为简单起见,我只关注 ThemeService
,但 GroupService
是相似的。 ThemeService
应该有一个内部 Subject
当调用 remove 时,Subject
将是下一个值(可能是整个新列表)。
StatisticsService
将订阅 ThemeService
observable 并在更改后重新计算。它看起来像这样
/* 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;
}
}
我有一个统计应用程序。在我页面的左侧,我有主题列表,在顶部 - 组列表。主要部分包含与主题和组相关的统计项。
我还有几个服务可以为我的应用程序提供业务逻辑。为简单起见,让我们谈谈其中三个:ThemeSerivce、GroupService 和 StatisticsService.
最终用户可以操作主题和组列表(添加或删除项目),每次更改后我都必须重新计算统计信息。在此应用程序中,我使用 Subjects 和 Subsription 来自 rx.js 来跟踪此类更改.
所以,在我的组件中我可以这样写:
对于 GroupComponent
removeGroup() {
this.groupService.removeGroup(this.group);
this.statisticsService.updateStatistics();
}
对于 ThemeComponent
removeTheme() {
this.themeService.removeTheme(this.theme);
this.statisticsService.updateStatistics();
}
但从逻辑上讲,这些组件不必了解统计信息。当然,我可以将 StatisticsService 的依赖项移动到 ThemeService 和 GroupService 中,但之后我将不得不调用statisticsService.updateStatistics() 在每个改变主题或组集合的方法中。这就是为什么我想通过订阅实现直接的跨服务通信。
最后是我的问题:
这是个好主意吗?
如果可以的话,最好的实现方式是什么? 当我在组件中使用 Subscription 时,我在 ngOnInit() 方法中注册它并在 ngOnDestroy()[=50= 中取消订阅] 以防止内存泄漏。 我可以在服务的构造函数中订阅它吗?我应该何时何地退订?或者当我在 App 模块级别将我的服务注册为提供商时,也许没有必要?
StatisticsService
应订阅主题和组列表。您的各个组件应该只订阅它们各自的服务(ThemeComponent 到 ThemeService,Group 到 Group 等)。
为简单起见,我只关注 ThemeService
,但 GroupService
是相似的。 ThemeService
应该有一个内部 Subject
当调用 remove 时,Subject
将是下一个值(可能是整个新列表)。
StatisticsService
将订阅 ThemeService
observable 并在更改后重新计算。它看起来像这样
/* 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;
}
}