# Manage Multiple Service Implementations

Parsley supports registering multiple services under the same contract type, allowing you to inject a list of these services into your application. While you can always resolve multiple services of the same contract using the ResolveRequiredServices[T] method, injecting them as an array or slice requires a list registration via the RegisterList[T] method.

This method facilitates the automatic injection of all registered services that share the same contract type, providing greater flexibility and scalability in managing multiple service implementations.

# Example

This example demonstrates registering and injecting a list of services sharing the same contract type using Parsley's RegisterList[T] feature. In the code, two data service constructor functions (NewLocalDataService and NewRemoteDataService) are registered, and then RegisterList[T] is used to group the service registrations under the DataService contract. Please note that both constructor functions must return the service instances as DataService objects to make this automation work.

package main

import (
	"context"
	"fmt"
	"github.com/matzefriedrich/parsley-docs/examples/registration-concepts/internal"
	"github.com/matzefriedrich/parsley/pkg/features"
	"github.com/matzefriedrich/parsley/pkg/registration"
	"github.com/matzefriedrich/parsley/pkg/resolving"
	"github.com/matzefriedrich/parsley/pkg/types"
)

func main() {

	registry := registration.NewServiceRegistry()

	registry.Register(internal.NewLocalDataService, types.LifetimeTransient)
	registry.Register(internal.NewRemoteDataService, types.LifetimeTransient)
	features.RegisterList[internal.DataService](registry)

	registry.Register(newAggregator, types.LifetimeTransient)

	resolver := resolving.NewResolver(registry)
	ctx := resolving.NewScopedContext(context.Background())
	aggregator, _ := resolving.ResolveRequiredService[*dataAggregationService](resolver, ctx)

	results := aggregator.fetchAll()
	for _, result := range results {
		fmt.Println(result)
	}
}

type dataAggregationService struct {
	dataServices []internal.DataService
}

func newAggregator(dataServices []internal.DataService) *dataAggregationService {
	return &dataAggregationService{
		dataServices: dataServices,
	}
}

func (a *dataAggregationService) fetchAll() []string {
	results := make([]string, 0)
	for _, dataService := range a.dataServices {
		data := dataService.FetchData()
		results = append(results, data)
	}
	return results
}

The dataAggregationService aggregates data from all registered DataService instances. When fetchAll() is called, it iterates over the injected list of DataService implementations, collects their data, and prints the results.

The printed output confirms that local and remote data services are successfully aggregated and utilized.

# Benefits and use cases

This feature is handy when working with multiple implementations of the same service contract, such as aggregating results from various sources or supporting different strategies for a given operation.

The RegisterList[T] method simplifies managing these services and ensures that all relevant implementations are easily accessible in a single injection. This is especially valuable in modular systems or scenarios requiring dynamic extension of service capabilities.