Теория 📔
July 19

Паттерн "Медиатор"

Рассмотрим пример, где у нас есть три компонента: ComponentA, ComponentB, и ComponentC, которые взаимодействуют друг с другом через посредника.

Для начала создадим сервис, который будет выступать в роли посредника:

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class MediatorService {
  private events = new Subject<any>();
  public events$ = this.events.asObservable();

  emit(event: string, payload: any) {
    this.events.next({ event, payload });
  }
}

Далее приступим к созданию всех компонентов. Начнем с ComponentA, он будет отправлять событие через посредника:

import { Component } from '@angular/core';
import { MediatorService } from './mediator.service';

@Component({
  selector: 'app-component-a',
  template: `<button (click)="sendMessage()">Send Message from A</button>`
})
export class ComponentA {
  constructor(private mediatorService: MediatorService) {}

  sendMessage() {
    this.mediatorService.emit('messageFromA', 'Hello from Component A');
  }
}

Компонент ComponentB будет подписываться на события и отправлять свои:

import { Component, OnInit, OnDestroy } from '@angular/core';
import { MediatorService } from './mediator.service';
import { Subscription } from 'rxjs';

@Component({
  selector: 'app-component-b',
  template: `
    <div *ngIf="message">{{ message }}</div>
    <button (click)="sendMessage()">Send Message from B</button>
  `
})
export class ComponentB implements OnInit, OnDestroy {
  private subscription: Subscription;
  message: string;

  constructor(private mediatorService: MediatorService) {}

  ngOnInit() {
    this.subscription = this.mediatorService.events$.subscribe(({ event, payload }) => {
      if (event === 'messageFromA') {
        this.message = payload;
      }
    });
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }

  sendMessage() {
    this.mediatorService.emit('messageFromB', 'Hello from Component B');
  }
}

Компонент ComponentC будет подписываться на события:

import { Component, OnInit, OnDestroy } from '@angular/core';
import { MediatorService } from './mediator.service';
import { Subscription } from 'rxjs';

@Component({
  selector: 'app-component-c',
  template: `<div *ngIf="message">{{ message }}</div>`
})
export class ComponentC implements OnInit, OnDestroy {
  private subscription: Subscription;
  message: string;

  constructor(private mediatorService: MediatorService) {}

  ngOnInit() {
    this.subscription = this.mediatorService.events$.subscribe(({ event, payload }) => {
      if (event === 'messageFromB') {
        this.message = payload;
      }
    });
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }
}

Далее все компоненты объединим в модуль:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';
import { ComponentA } from './component-a';
import { ComponentB } from './component-b';
import { ComponentC } from './component-c';

@NgModule({
  declarations: [
    AppComponent,
    ComponentA,
    ComponentB,
    ComponentC
  ],
  imports: [
    BrowserModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

<app-component-a></app-component-a>
<app-component-b></app-component-b>
<app-component-c></app-component-c>

В этом примере ComponentA отправляет сообщение через MediatorService, ComponentB получает это сообщение и отображает его, а также может отправить своё сообщение, которое затем получает ComponentC. Таким образом, все компоненты взаимодействуют через посредника, минимизируя прямую связанность между ними.