Aggrregating multiple service providers

Hi all,

I am looking for advice on the best pattern to do the following:

My app has 10 service providers to service the state of 10 different data types. Their classes are all extending a base generic class to cater for common CRUD operations on these entities (as easier implemention of something like ngrx).

For cases like login/logout and save/load of data, I want to create a simple way to invoke same methods (e.g. getters) for all in one go.

What would be the most efficient way to achieve this?

What I have done now - with somehow satisfactory results (even though a bit unpredictable) is:
1 Create an service that injects all of the 10
2 The service holds an array of all services
3 I iterate the array to invoke methods like the getter

Sample code:

  constructor(
    private buyinginterestService: BuyinginterestService,
    private buyingopportunityService: BuyingOpportunityService,
    private buyingNeedService: BuyingNeedService,
    private commodityService: CommodityService,
    private countryService: CountryService,
    private converstationReviewService: ConversationReviewService,
    private plotService: PlotService,
    private priceService: PriceService,
    private productionService: ProductionService,
    private purchaseService: PurchaseService,
    private userService: UserService,

    private firebaseService: FirebaseService,
    private storage: Storage,
  ) {
    this.stateProviderList = [
      this.buyinginterestService,
      this.buyingopportunityService,
      this.buyingNeedService,
      this.commodityService,
      this.converstationReviewService,
      this.countryService,
      this.plotService,
      this.priceService,
      this.productionService,
      this.purchaseService,
      this.userService
    ];



and saving to localstorage for example

    this.stateProviderList
      .forEach(provider => {
        const savePath = this.localSavePath + '-' + provider.getUniqueKey();
        provider.getState$()
          .pipe(take(1))
          .toPromise()
          .then(state => {
            console.log('Save local state: ', savePath, state);
            this.storage.set(savePath, state);
          });
      });

Issues I have with this pattern is that it seems that the array appears empty (console.log) but is filled (?), and only after a few other actions, these methods invoke. Probably I am assuming too much of what actually happens under the hood in Angular

Any thoughts are very welcome

Regards

Tom

You are probably going to want to wait for further answers on this, because mine is unlikely to be popular.

The most charitable thing I can say about inheritance of implementation is that it’s hard to do well. By which I guess I mean I’ve never managed it. Every time I’ve started out with a design like this, I’ve ended up either regretting it, scrapping it, or both.

If I had 10 service providers that were similar enough that I contemplated having them inherit from a common base class, I would take that as a hint that I should do one of two things:

  • simply merge them all into a single provider
  • create an under-the-hood generic provider that the 10 inject, instead of inherit from, that does all the heavy lifting and what-would-be-duplicated code

Inheritance for declaring extension of interface I think has value, but inheritance for reusing implementation details I would avoid.

Is it perhaps worth at least going through a mental “what if?” exercise of thinking about the pros and cons of a single service that manages all 10 of these business objects? The obvious “con” would probably be code size of that single provider, but there would seem to be several tempting "pro"s.

Hi, and thx for these considerations. Indeed, the injectable approach seems better then inheritance. I assume on bundle size at least (UX) and the DX side maybe also a bit more less demanding on figuring out underlying magic.

It felt ackward creating an array of providers and whith these approaches maybe it becomes easier. Just have to mak sure type-safety retains. I will put it on the backlog.

Thx again, best wishes for the new year and looking forward to many learnings from this forum.

Regard
Tom

Generics can often help in situations like this.