Angular 循环依赖解决方案

Angular Circular Dependency Solution

如何解决这个循环依赖问题?

备注:

你的服务不应该知道组件,如果你的服务知道组件,那就是糟糕的设计。您应该在您的服务中有一个类似行为主题的可观察对象,并让您的组件订阅可观察对象以了解何时弹出新消息。

为您服务

message$ = new BehaviourSubject<string>(null);

以及一个将消息发送到管道的函数。

nextMessage(message: string) {
  this.message$.next(message);
}

然后在您的组件中订阅 message$ observable 然后弹出。

this.messageSubscription = this.service.message$.subscribe(message => { this.popup(message); });

确保在 ngDestroy 上执行 takeUntil 或 unscbscribe。

ngOnDestroy() {
  if (this.messageSubscription ) {
    this.messageSubscription.unsubscribe();
  }
}

您可以做的是从 PopupService 中删除弹出窗口创建逻辑。这是给你的一个小重构。

使用 PopupService 仅从应用程序的不同部分创建事件。

@Injectable()
export class PopupService {
    private _alert: Subject<any> = new Subject();
    private _yesno: Subject<any> = new Subject();
    private _custom: Subject<any> = new Subject();

    // since you didn't like the on- methods, you can do following
    public readonly alert$ = this._alert.asObservable();
    public readonly yesno$ = this._yesno.asObservable();
    public readonly custom$ = this._custom.asObservable();

    onAlert() { return this._alert.asObservable(); }

    onYesno() { return this._yesno.asObservable(); }

    onCustom() { return this._custom.asObservable(); }

    alert(payload) { this._alert.next(payload); }
    yesno(payload) { this._yesno.next(payload); }
    custom(payload) { this._custom.next(payload); }
}

所以,我们有一个 PopupService,它只发出一些带有 payload 的事件。我在这里使用 Subject 是因为以后的订阅者不需要知道之前是否有 alertyesno 事件。如果你想有这样的逻辑,你可以把Subject改成BehaviorSubject

创建一个名为 PopupManager 的组件并在 app.component

中使用它

app.component.ts

@Component({
    selector: 'app-root',
    template: `
        <!-- some template -->
        <app-popup-manager></app-popup-manager>
    `
})
export class AppComponent {}
@Component({
   selector: 'app-popup-manager',
   template: '' // don't need to have template
})
export class PopupManagerComponent implements OnInit {
   constructor(private matDialog: MatDialog, private popupService: PopupService) {}

   ngOnInit() {
       this.popupService.onAlert().subscribe(payload => {
       //   this.matDialog.open...
       });

       this.popupService.onYesno().subscribe(payload => {
       //   this.matDialog.open...
       });

       this.popupService.onCustom().subscribe(payload => {
       //   this.matDialog.open...
       });
   }
}

通过这种方式,您可以在您想要的任何组件中使用 PopupService,因为它现在是一个单独的独立服务。

为什么不应该将 Subject 暴露给外界?

你可以想到这个封装class字段。您确实可以将 _alert 暴露给外界,但您将无法控制谁以何种方式使用该主题。方法始终是提供功能同时保持对字段的一些控制的好方法。将来,您可能想要更改服务的内部结构,也许是某些主题。如果您让应用程序的其他部分直接访问字段,您将不得不进行大量重构。但是这样一来,既然你给了他们一些方法,只要你不破坏这些方法就可以了。