简体   繁体   中英

How to use Dependency Injection with the Facade pattern?

I am using autofac in my UWP application.

I am using the facade pattern for my backend and it is represented by an IFacade interface.

public interface IFacade 
{
    /* forwards view-models' calls to different parts of the backend */
}

The view-models of my UWP application are using an implementation of IFacade whose concrete implementation is resolved through autofac in the UWP's App instance.

public class App : Application
{
    ...

    private IFacade InitializeDependencies()
    {
        var containerBuilder = new ContainerBuilder();

        //  Registers all the platform-specific implementations of services.
        containerBuilder.RegisterType<LoggingService>().As<ILoggingService>().SingleInstance();
        containerBuilder.RegisterType<SQLitePlatformService>().As<ISQLitePlatformService>().SingleInstance();
        containerBuilder.RegisterType<DiskStorageService>().As<IDiskStorageService>().SingleInstance();
        containerBuilder.RegisterType<IdentityProviderFactoryService>().As<IIdentityProviderFactoryService>().SingleInstance();
        containerBuilder.RegisterType<DefaultVaultService>().As<IVaultService>().SingleInstance();
        containerBuilder.RegisterType<LocationService>().As<ILocationService>().SingleInstance();
        containerBuilder.RegisterType<NavigationService>().As<INavigationService>().SingleInstance();

        //  Registers all the dependencies of the Backend project.
        var backendDependencies = new Dependencies();
        backendDependencies.Setup(containerBuilder);

        //  Resolves the IFacade.
        var container = containerBuilder.Build();
        var lifetimeScope = container.BeginLifetimeScope();

        return backendDependencies.ResolveFacade(lifetimeScope);
    }

I have a lot of services in my backend and my implementation of IFacade ends up with that horrific constructor referencing a lot of services' interfaces, something would make Uncle Bob cringe.

internal sealed Facade : IFacade
{
    public Facade(ISessionService sessionService, IEntitiesRepository entitiesRepository, ISynchronizationService synchronizationService, IVaultService vaultService, IIdentityProviderFactoryService identityProviderFactoryService, IDemoTapeService demoTapeService, IDiskStorageService diskStorageService)
    {
        /* Saves the references as read-only fields. */
    }
}

Question

Contrary to the ServiceLocator, using DI forces us to make all the dependencies that are needed visible. I am not sure if I am using the Dependency Injection properly.

What can I do so that my constructor of my Facade class does not have that many parameters?

Solutions tried

  1. Properties

I could change the Facade class and inject the services through public properties. I am not fond of lots of public get / set as my IFacade contract would now indicate that those properties could be changed after the Facade implementation is created, which is not something I want to support (and debug).

  1. Aggregate interfaces

Another option would be to aggregate interfaces together (something that I call the SomethingContext classes) but then it is harder to understand what these groups of interfaces would mean.

  1. Inject a ServiceLocator that is not static in the Facade constructor

The last solution that seems more acceptable (well... acceptable to me) would be to use DI to inject a non-static ServiceLocator. It is kind of solution 2). However, I know the ServiceLocator is something that is frowned upon .

So one another approach is to create some smaller Facade Services and then inject those services to the main facade.

For example you can create such smaller facade for INavigationService and ILocationService :

public class GeographyService : IGeographyService
{
    public GeographyService(
        INavigationService navigationService, 
        ILocationService locationService)
    { 
    }
}

The same is true for ISQLitePlatformService and DiskStorageService :

public class StorageService : IStorageService 
{
    public StorageService(
        ISQLitePlatformService databaseService, 
        DiskStorageService diskStorageService)
    { 
    }
}

That's of course only an example of an idea.

Such an approach is generally considered better than aggregate services with all the dependencies aggregated ( http://autofaccn.readthedocs.io/en/latest/advanced/aggregate-services.html ) or ServiceLocator (anti-)pattern. You can also read some thoughts about it here: http://blog.ploeh.dk/2010/02/02/RefactoringtoAggregateServices/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM