Закрытая тема и общедоступная тема c только для чтения в общих службах - PullRequest
2 голосов
/ 21 февраля 2020

Я начал работать над проектом angular 8, в котором два родственных компонента должны обмениваться данными. До сих пор подход состоял в том, чтобы EventEmitter был в родительской службе. Затем дочерние компоненты вызвали методы emit для этих эмиттеров, чтобы передать данные другому брату. Вот пример случая:

Shared Service: (плохо)

@Injectable()
export class DocumentViewerService {
    public readonly annotationDeletedInAnnotationPanel = new EventEmitter<string>();

Дочерний компонент: (плохо)

this.documentViewerService.annotationDeletedInAnnotationPanel.emit(annotationId);

Однако я обнаружил несколько онлайн-источников ( 1 , 2 ), которые утверждают, что использование EventEmitters в Сервисах является плохой практикой.

Вместо этого большинство онлайн-источников ( 3 , 4 ) предлагают шаблон, использующий Темы и общие службы для родственного общения.

Общий сервис: (хорошо)

@Injectable()
export class DocumentViewerService {
   private deletedAnnotationInAnnotationPanel$ = new Subject<string>();
   public readonly deletedAnnotationInPanel$ = this.deletedAnnotationInAnnotationPanel$.asObservable();

   deleteAnnotationInPanel(annotationId: string) {
        this.deletedAnnotationInWebViewer$.next(annotationId);
   }

Дочерний компонент: (хорошо)

this.documentViewerService.deleteAnnotationInPanel(id);

Оба подхода оставляют у меня несколько вопросов:

  1. Почему плохой практикой является использование EventEmitters в Service . Вам не нужно помещать тег @Output, и он будет действовать подобно наблюдаемому при вызове с помощью emit в одном из дочерних элементов.
  2. Какая причина сделать Субъект личным в предположительно лучшем подходе? Дочерние компоненты по-прежнему могут изменять значения, вызывая предоставленный метод deleteAnnotationInPanel (в приведенном выше примере).
  3. В чем разница в создании объекта Subject deleteAnnotationInAnnotationPanel $ Приватное и публичное c Только для чтения . Последний позволит всем подписаться и вызвать .next, но не изменять инициализацию. Вместо пяти строк кода у меня была бы только одна:

    publi c readonly deleteAnnotationInPanel $ = new Subject ();

Ни один из сетевых источников не кажется объяснить, почему нужно сделать Предмет закрытым с помощью метода установки и дополнительной публикации, доступной для детей.

Надеюсь, вы можете дать мне несколько веских аргументов или понять, почему один должен быть предпочтительнее других. Заранее спасибо за поддержку!

Ответы [ 2 ]

1 голос
/ 21 февраля 2020
  1. Почему использование EventEmitters в Сервисе является плохой практикой. Вам не нужно ставить тег @Output, и он будет действовать аналогично наблюдаемому при вызове с помощью emit у одного из дочерних элементов.

Команда Angular не гарантирует этот EventEmitter всегда будет действовать как наблюдаемая, и использование его в качестве наблюдаемой не рекомендуется. EventEmitters - это абстракция пользовательских событий, им нет места в службах, которые должны быть изолированы от пользовательского интерфейса.

В чем причина сделать Субъект закрытым в предположительно лучшем подходе? Дочерние компоненты могут по-прежнему изменять значения, вызывая предоставленный метод deleteAnnotationInPanel (в примере выше).

Это все о создании собственного интерфейса для взаимодействия различных областей вашего приложения. Когда вы создаете свой собственный API-интерфейс службы, вы контролируете его и можете вносить изменения в реализацию без изменения интерфейса.

Какая разница в том, чтобы сделать Предмет удаленнымAnnotationInAnnotationPanel $ private против publi c только для чтения. Последний позволит всем подписаться и вызвать .next, но не изменять инициализацию. Вместо пяти строк кода у меня будет только одна:

Раскрытие необработанного предмета означает, что любой компонент может завершить предмет и испортить вечеринку для всех остальных. Это довольно опасно. Предоставьте только то поведение, которое необходимо для поддержания контроля.

Еще несколько строк кода, которые гораздо легче обслуживать, гораздо лучше, чем меньшее количество строк кода, которые могут вызвать хаос в непринужденной среде.

1 голос
/ 21 февраля 2020
  1. Почему использование EventEmitters в Service является плохой практикой.

    EventEmitter предназначено для использования в компонентах. Как сказано в документации,

    Используется в компонентах с директивой @Output для генерации пользовательских событий синхронно или асинхронно ...

    Даже при том, что он имеет некоторую семантику Subject, он не предназначен для этой цели.

  2. Какая причина сделать Субъект частным в предположительно лучшем подходе?

    Субъект похож на состояние вашего класса Service, вы не хотите показывать его публично, а остальные приложения начинают вызывать события из него. Вы хотите, чтобы служба генерировала события только тогда, когда наблюдатели должны быть проинформированы о реальных событиях. Таким образом, при написании таких методов, как deleteAnnotationInPanel, вы создаете уровень абстракции и гарантируете, что пользователи службы выполняют действия, используя службу, и некоторые из этих действий могут привести к запуску событий.

  3. Какая разница в том, чтобы сделать Предмет удаленнымAnnotationInAnnotationPanel $ private против publi c только для чтения.

    Если вы сделаете это private, пользователи класса обслуживания не будут иметь к нему доступа, и никто не сможет подписаться на события, публикуемые по теме. Таким образом, сделать это public readonly неизбежно. Вы хотите, чтобы это было readonly, потому что вы не хотите, чтобы мошеннический код перезаписывал его, чтобы он был наблюдателем для какого-то другого субъекта и начинал без необходимости генерировать события.

...