Использование нескольких экземпляров одного и того же сервиса

У меня есть сервис, как это:

@Injectable()
export class EditorService { ... }

И у меня есть компонент, как это:

@Component({
    ...
    template: '<child-component></child-component>',
    providers: [EditorService],
    ...
})
export class SomeComponent {
    constructor(
        private _appleEditorService: EditorService,
        private _pearEditorService: EditorService) {}
}

Как вы могли заметить, этот компонент имеет дочерний компонент:

@Component({
    ...
    selector: 'child-component',
    ...
})
export class ChildComponent {
    constructor(
        private _appleEditorService: EditorService,
        private _pearEditorService: EditorService) {}
}

Как видите, я хочу два экземпляра моего EditorService: один будет использоваться для редактирования яблок, а другой - для редактирования груш. Однако приведенный выше код не сработает, поскольку Angular не может узнать, какой экземпляр EditorService какой, а их имена переменных являются частными. _pearEditorService в ChildComponent может также ссылаться на тот же экземпляр, что и _appleEditorService в SomeComponent.

Вопрос: Как еще я могу использовать один и тот же сервис Angular2 дважды?

РЕДАКТИРОВАТЬ: Суть моего вопроса, если это возможно, используя тот же класс. Я знаю, что есть обходные пути, фактически создавая отдельный класс для каждого экземпляра службы, и даже делая это с небольшим количеством кода по наследству. Я просто хочу знать, можно ли это сделать без.

Ответ 1

Angular DI поддерживает один экземпляр для каждого поставщика. В вашем случае, если у вас есть два параметра конструктора одного типа, они разрешаются в одном экземпляре.

Что вы можете сделать, так это предоставить фабричную функцию (отличную от простого useFactory провайдера useFactory хотя она также использует его)

(Пример скопирован с fooobar.com/questions/628117/...)

{ provide: EditorService, useFactory: 
    (dep1, dep2) => {
        return (x) => { 
            new EditorService(x, dep1, dep2);
        }
    }, deps: [Dep1, Dep2]
})

....

constructor(@Inject(EditorService) editorServiceFactory: any) {
  let editorService1 = editorServiceFactory(1);
  let editorService2 = editorServiceFactory(2);
}

Если у вас есть фиксированное количество экземпляров, это должно работать:

{ provide: 'instance1', useClass: EditorService },
{ provide: 'instance2', useClass: EditorService },
export class SomeComponent {
    constructor(
        @Inject('instance1') private _appleEditorService: EditorService,
        @Inject('instance2') private _pearEditorService: EditorService) {}
}

Ответ 2

может переосмыслить ваш дизайн

Думаю, вам, возможно, придется переосмыслить свой дизайн в целом. Какой смысл иметь две переменные, которые указывают на тот же самый редактор? Если они используют одну и ту же реализацию.

Решение наследования

Решением этого может быть использование Наследования. Я не видел ваших услуг, поэтому я не уверен, что они делают, но из этого кода я предполагаю, что функциональность "яблоко" и функциональность "груша" на самом деле разные. Затем это указывает на то, что у вас могут возникнуть проблемы с дизайном, и ваш редактор может сделать слишком много. Возможно, вы могли бы переместить код, похожий как на Яблоки, так и на Pears, на службу под названием EditorService, а затем расширить два класса. a AppleEditorService и a PearEditorService.

Использовать общий метод fruitService

Просто поговорим немного больше о том, почему, я думаю, вам может понадобиться переосмыслить ваш дизайн. Предположим, что аплеты и груши действительно имеют одинаковую функциональность. Таким образом, EditorService делает то же самое. Вы хотите, чтобы одна переменная использовалась для "Яблок" и одна для "Груши". Если я увижу этот код (предположим, что другие люди работают в вашей команде), и я замечаю, что обе переменные указывают на одну и ту же службу. (Услуги - это одиночные игры), я просто соблазню удалить это и сделать что-то вроде fruitService : EditorService или что-то вроде этого.

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


Но, как я уже говорил ранее. Подумайте о своем дизайне. Вам действительно нужны две детские услуги, или вы можете решить ее по-другому? Можете ли вы иметь яблоки и груши только подклассы фруктов? Можете ли вы просто использовать одну переменную 'fruitService' вместо обоих яблок/груш? Что происходит, когда вы хотите хранить "Клубнику", а также в будущем? Наличие связки переменных относится к одной и той же службе (потому что они делают то же самое), но с разными именами переменных это не очень хорошая идея. Представьте, что вы видите это в коде

 appleService = EditorService;
 pearService = EditorService;
 starwberryService = EditorService;
 lemonService = EditorService;
 ...
 guavaService = EditorService;

Не означает ли это, что что-то странно с кодом? Я могу представить (вы не указали код на данный момент), что вы храните Массив из фруктов. Но тогда, возможно, fruitService мог бы работать, а затем хранить fruitService.store(Apple a) и помещать его в массив "фруктов". Использовать "фильтр" для получения правильных фруктов из массива не должно быть слишком сложно.

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

Ответ 3

Не идеально, но если вы создадите модуль для каждого компонента, а затем импортируете свой сервис для каждого модуля, у вас будет 2 экземпляра одного и того же сервиса (по одному для каждого модуля).