【问题标题】:How to use Dependency Injection with the Facade pattern?如何将依赖注入与 Facade 模式一起使用?
【发布时间】:2018-09-25 11:12:44
【问题描述】:

我在我的 UWP 应用程序中使用 autofac

我在后端使用facade 模式,它由IFacade 接口表示。

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

我的 UWP 应用程序的视图模型正在使用 IFacade 的实现,其具体实现通过 UWP 的 App 实例中的 autofac 解决。

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);
    }

我的后端有很多服务,而我对 IFacade 的实现最终导致那个可怕的构造函数引用了很多服务的接口,这会让 Bob 大叔畏缩不前。

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. */
    }
}

问题

与 ServiceLocator 不同,使用 DI 迫使我们使所有需要的依赖项可见。我不确定我是否正确使用了依赖注入。

我该怎么做才能使我的Facade 类的构造函数没有那么多参数?

已尝试的解决方案

  1. 属性

我可以更改Facade 类并通过公共属性注入服务。我不喜欢很多public get / set,因为我的IFacade 合同现在表明这些属性可以在创建Facade 实现后更改,这不是我想要支持(和调试)的东西。

  1. 聚合接口

另一种选择是将接口聚合在一起(我称之为SomethingContext 类),但是很难理解这些接口组的含义。

  1. Facade 构造函数中注入一个非静态的ServiceLocator

最后一个似乎更可接受的解决方案(嗯……我可以接受)是使用 DI 注入非静态 ServiceLocator。这是一种解决方案2)。但是,我知道 ServiceLocator 是 frowned upon

【问题讨论】:

  • 带有构造函数注入的 DI 非常适合您真正需要的所有依赖项。我建议仅对可选依赖项使用属性注入

标签: c# .net uwp autofac


【解决方案1】:

所以另一种方法是创建一些较小的外观服务,然后将这些服务注入主外观。

例如,您可以为INavigationServiceILocationService 创建这样更小的外观:

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

ISQLitePlatformServiceDiskStorageService 也是如此:

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

这当然只是一个想法的例子。

这种方法通常被认为比聚合所有依赖项(http://autofaccn.readthedocs.io/en/latest/advanced/aggregate-services.html)或 ServiceLocator(反)模式的聚合服务更好。你也可以在这里阅读一些关于它的想法:http://blog.ploeh.dk/2010/02/02/RefactoringtoAggregateServices/

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2018-02-22
  • 1970-01-01
  • 1970-01-01
  • 2019-06-05
  • 2021-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多