【问题标题】:Abstract Factory fit into Unity抽象工厂适合 Unity
【发布时间】:2015-03-13 05:30:19
【问题描述】:

我们正在构建一个应用程序,该应用程序具有与其他系统的多个集成接触点。我们正在有效地使用 Unity 来满足我们所有的依赖注入需求。整个业务层是使用接口驱动的方法构建的,在应用程序的引导过程中将实际实现注入到外部组合根中。

我们希望以优雅的方式处理集成层。业务类和存储库依赖于IIntegrationController<A, B> 接口。几个IIntegrationController<A, B> 实现一起代表在后台与一个目标系统集成——形成一个集成层。目前,我们在一开始就连接了合成根中的所有内容,一个镜头。此接口的使用者也预先注册了适当的InjectionConstrutorResolvedParameter。大多数类型都使用PerResolveLifetime 操作,使用IIntegrationController 的业务类也针对每个请求上下文单独解析。

参考下面的代码。

        // IIntegrationController Family 1
        // Currently the default registration for IIntegrationController types injected into the business classes
        container.RegisterType<IIntegrationController<A, B>, Family1-IntegrationController<A, B>>();
        container.RegisterType<IIntegrationController<C, D>, Family1-IntegrationController<C, D>>();

        // IIntegrationController Family 2 (currently not registered)
        // We want to be able to register this, or manage this set of mapping registrations separately from Family 1,
        // and be able to hook these up dynamically instead of Family-1 on a per-resolve basis
        container.RegisterType<IIntegrationController<A, B>, Family2-IntegrationController<A, B>>();
        container.RegisterType<IIntegrationController<C, D>, Family2-IntegrationController<C, D>>();

        // Repository/Business Class that consume IIntegrationControllers.
        // There is a whole family of IIntegrationController classes being hooked in, 
        // and there are multiple implementations for the family (as shown above). A typical AbstractFactory scenario.
        container.RegisterType(typeof(Repository<Z>), new PerResolveLifetimeManager(),
            new InjectionConstructor(
                new ResolvedParameter<IIntegrationController<A, B>>(), 
                new ResolvedParameter<IIntegrationController<C, D>>())
        );

问题陈述:

我们希望能够在运行时切换整个IIntegrationController&lt;A, B&gt; 系列。在解析业务类时,我们希望根据上下文中可用的请求参数为其注入正确版本的IIntegrationController&lt;A, B&gt;

  • 基于“命名”注册的解决方案将无法扩展,原因有两个(必须切换整个集成类系列,并且需要笨拙的名称注册和代码中的条件解析,因此难以维护) .
  • 即使存在解决方案链/层次结构,该解决方案也应该可以工作,即 IIntegrationController 的直接消费者也通过 Unity 解决,因为它是动态注入到另一个类中的。
  • 我们在解析过程中尝试了DependencyOverrideResolveOverride 类,但这需要覆盖整个Family-2 IIntegrationController 解析集,而不是仅仅能够切换整个层。李>
  • 我们了解到,可能必须注入 AbstractFactory,而不是直接将 IIntegrationController 注入业务类,但我们无法使其正常工作,并且不确定注册和解析会发生在哪里。如果业务类与 AbstractFactory 挂钩,首先我必须在每次解析时连接正确的工厂,
  • 这是否需要覆盖InjectionFactoryThis link 提出了一种方法,但我们无法让它顺利运行。

【问题讨论】:

    标签: c# dependency-injection unity-container abstract-factory


    【解决方案1】:

    您的设计的优点在于您已经有了正确的抽象。您使用通用抽象,因此只需在您已经 SOLID 设计的基础上应用正确的模式即可解决问题。

    换句话说,使用代理:

    // This class should be considered part of your composition root.
    internal class IntegrationControllerDispatcher<TRequest, TResult> 
        : IIntegrationController<TRequest, TResult>
    {
        private readonly IUserContext userContext;
        private readonly Family1_IntegrationController<A, B> family1Controller;
        private readonly Family2_IntegrationController<A, B> family2Controller;
    
        public IntegrationControllerDispatcher(
            IUserContext userContext,
            Family1_IntegrationController<A, B> family1Controller,
            Family2_IntegrationController<A, B> family2Controller) {
            this.userContext = userContext;
            this.family1Controller = family1Controller;
            this.family2Controller = family2Controller;
        }
    
        public TResult Handle(TRequest request) {
            return this.GetController().Handle(request);
        }
    
        private IIntegrationController<TRequest, TResult> GetController() {
            return this.userContext.IsInFamily("family1"))
                ? this.family1Controller
                : this.family2Controller;
        }
    }
    

    有了这个类,你的整个配置可以简化为:

    container.RegisterType<IUserContext, AspNetUserContext>();
    
    container.RegisterType( 
        typeof(IIntegrationController<,>), 
        typeof(IntegrationControllerDispatcher<,>));
    
    container.RegisterType(typeof(Repository<>), typeof(Repository<>));
    

    注意以下几点:

    • 请注意执行开放通用映射的注册的使用。您不必一一注册所有封闭版本。只需一行代码即可完成。
    • 另请注意,不同系列的类型不是 挂号的。 Unity 可以自动解决它们,因为我们的 IntegrationControllerDispatcher 直接依赖于它们。这 类是一段基础架构逻辑,应该放在里面 你的作曲根。
    • 请注意,使用特定系列实现的决定不是在构建对象图期间做出的;它是在运行时生成的,因为确定它的值是运行时值。在构建对象图时尝试确定这一点,只会使事情复杂化,并使验证您的对象图变得更加困难。
    • 此外,此运行时值在函数调用之后被抽象出来并置于抽象之后(在本例中为IUserContext.IsInFamily,但这当然只是一个示例)。

    【讨论】:

    • 现实生活中的实现对我来说不是很清楚。您能否添加对使用这种方法的一些代码的引用?当然,如果你有的话。
    猜你喜欢
    • 1970-01-01
    • 2015-01-01
    • 2011-01-05
    • 1970-01-01
    • 2014-01-14
    • 1970-01-01
    • 2014-05-03
    • 2013-10-17
    • 1970-01-01
    相关资源
    最近更新 更多