依赖注入:避免在启动时加载所有内容

7
我正在尝试使用依赖注入(Dependency Injection)与MVP模式,在构造函数中注入所需的依赖项。问题在于,如果我将依赖注入应用于根MainWindowPresenter,则所有子Presenter、它们的子Presenter、视图和服务都会在启动时被加载。由于所有内容都是直接或间接地从MainWindowPresenter加载的,这意味着整个应用程序将在启动时全部加载到内存中。
我知道在.NET中创建所有对象可能不会花费太多,但我无法不考虑它们永远不会同时被使用时的内存浪费。例如AboutPresenter或HelpPresenter可能根本不会被使用。我有遗漏吗?或这就是依赖注入应该工作的方式?有没有解决这个问题的方法?
我唯一找到的解决办法是使用工厂,以便在需要时创建子Presenter/视图/服务。例如:
class HelpFactory : AbstractHelpFactory
{
    public IHelpPresenter Create()
    {
         IHelpService helpService = new ConcreteHelpService();
         IHelpView helpView = new ConcreteHelpView();

         HelpSearchPresenter searchPresenter = HelpSearchFactory.Create();

         return HelpPresenter(helpView, helpService, searchPresenter);
    }
}

这基本上与工厂依赖子工厂的情况相同,但至少它们比presenters/views/services更轻,并且在需要之前不需要加载子工厂。

1个回答

2

有几种可能的解决方案(从一般到具体排列):

组合根

确定一个组合根 (Composition Root)这是应用程序中 (最好是) 独特的位置,用于将模块组合在一起这是将所有依赖项组合在一起的首选解决方案

抽象工厂

而不是注入依赖项,您可以注入 类似的 依赖项工厂。这将帮助您推迟依赖项的创建,并仅解决当前情况下所需的依赖项。例如使用ninject.extension.factory

kernel.Bind<IDependencyFactory>().ToFactory();

kernel
    .Bind<IDependency>()
    .To<DependencyImpl1>()
    .NamedLikeFactoryMethod((IDependencyFactory f) => f.GetJob());

var abstractFactory = kernel.Get<IDependencyFactory>();

var dependency = abstractFactory.GetJob(); 

public abstract class IDependency { }
public class DependencyImpl1 : IDependency { }
 
public interface IDependencyFactory
{
    IDependency GetJob();
    Lazy<IDependency> GetLazyJob();
}

这也有助于避免过度注入类,例如构造函数过度注入。
聚合服务
不要注入依赖项,而是注入聚合处理例程的服务。阅读更多内容请访问Refactoring to Aggregate Services 延迟加载
有时需要推迟解决依赖关系,原因可能是在启动期间创建成本过高和/或很少使用。在这些情况下,可以使用Lazy而不是IDependency进行注入。 使用Ninject.Extension.Factory的示例
kernel
    .Bind<Lazy<IDependency>>()
    .To<Lazy<IDependency>>()
    .NamedLikeFactoryMethod((IDependencyFactory f) => f.GetLazyJob());

var abstractFactory = kernel.Get<IDependencyFactory>();

var lazyDependencyUsingFactory = abstractFactory.GetLazyJob();

使用无工厂的延迟加载示例:

kernel
    .Bind<IDependency>()
    .To<DependencyImpl1>();
    
kernel
    .Bind(typeof (Lazy<>))
    .ToMethod(context =>
            ((ILazyLoader) Activator.CreateInstance(typeof (LazyLoader<>).MakeGenericType(context.GenericArguments),
                                                    new object[] { context.Kernel })).Loader);

var lazyDependency = kernel.Get<Lazy<IDependency>>();

lazyDependency.Dump();
lazyDependency.Value.Dump();

注意: 完整的示例可在此处找到。

这是一个关于IT技术的相关内容。

谢谢您的帮助,我认为对我来说最好的方法是懒加载。 - user1997244

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接