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

Скажем, у вас есть компонент, обладающий большой функциональностью. Допустим, это аудиоплеер. Итак, вы бы начали с чего-то вроде этого:

@Component({
  selector: 'audio-player',
  templateUrl: './audio-player.component.html',
  styleUrls: ['./audio-player.component.less'],
  encapsulation: ViewEncapsulation.None
})
export class AudioPlayerComponent {}

Теперь, чтобы этот проигрыватель работал, вам нужно будет загрузить звук, возможность пропускать треки, воспроизводить, приостанавливать и останавливать. Вы даже можете загрузить некоторые метаданные о песне из другого сервиса. Может быть, было бы неплохо даже показать предстоящие заголовки из плейлиста.

Итак, теперь ваш конструктор выглядит примерно так:

constructor(private audioLoader: AudioLoaderService,
            private audioPlayerService: AudioPlayerService,
            private audioMetadata: AudioMetadataService,
            private playlistService: PlaylistService) {}

Теперь это только начало, и зависимости будут расти по мере добавления новых функций. Это может начать выходить из-под контроля и становиться труднее тестировать по мере роста списка зависимостей. Ах, что ты собираешься делать?

Шаблон прокси

Шаблон прокси - это просто создание новой службы, которая объединяет все эти зависимости и предоставляет только методы из тех зависимостей, которые необходимы компоненту, путем предоставления методов, которые просто передаются методам этих служб. Таким образом, приведенный выше конструктор становится:

constructor(private proxyService: ProxyAudioPlayerService) {}

А сервис Proxy может выглядеть примерно так:

class ProxyAudioPlayerService {
  constructor(/*your dependencies*/){}
 
  loadAudio(id: string){
    return this.audioLoader.load(id);
  }
 
  play() {
    return this.audioPlayerService.play();
  }
  pause() {
    return this.audioPlayerService.pause();
  }
  ... and so on
}

Теперь это похоже на отличный способ очистить ваш компонент! Так что в этом плохого?

Эта проблема

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

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

Независимо от вашего варианта использования, если вы видите этот шаблон, вам следует подумать о разделении компонентов, прежде чем переходить по этому пути. Аргументы в пользу преимуществ также легко опровергнуть. Это не может помочь с тестированием, так как теперь вам также нужно протестировать прокси-службу, а проблема тестирования с большим набором зависимостей все еще возникает. Вы также создали новый уровень абстракции, чтобы ваш конструктор оставался чистым, но вся сложность вашего кода осталась. Это просто перемещает проблему из компонента в службу.

Так что не делай этого

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