相关疑难解决方法(0)

依赖注入和服务定位器模式之间有什么区别?

这两种模式看起来都像是控制反转原理的实现.也就是说,一个对象不应该知道如何构造它的依赖关系.

依赖注入(DI)似乎使用构造函数或setter来"注入"它的依赖项.

使用构造函数注入的示例:

//Foo Needs an IBar
public class Foo
{
  private IBar bar;

  public Foo(IBar bar)
  {
    this.bar = bar;
  }

  //...
}
Run Code Online (Sandbox Code Playgroud)

服务定位器似乎使用了一个"容器",它连接了它的依赖关系并给它foo吧.

使用服务定位器的示例:

//Foo Needs an IBar
public class Foo
{
  private IBar bar;

  public Foo()
  {
    this.bar = Container.Get<IBar>();
  }

  //...
}
Run Code Online (Sandbox Code Playgroud)

因为我们的依赖项只是对象本身,所以这些依赖项具有依赖项,它们具有更多依赖项,依此类推.因此,控制容器的反转(或DI容器)诞生了.示例:Castle Windsor,Ninject,Structure Map,Spring等)

但是,IOC/DI容器看起来完全相同像一个服务定位器.将它称为DI容器是一个坏名字?IOC/DI容器只是另一种服务定位器吗?当我们有很多依赖关系时,我们使用DI容器这一事实的细微差别是什么?

design-patterns dependency-injection service-locator

271
推荐指数
11
解决办法
7万
查看次数

ServiceLocator是反模式吗?

最近我读过Mark Seemann关于Service Locator反模式的文章.

作者指出ServiceLocator为反模式的两个主要原因:

  1. API使用问题(我完全可以使用)
    当类使用服务定位器时,很难看到它的依赖关系,因为在大多数情况下,类只有一个PARAMETERLESS构造函数.与ServiceLocator相比,DI方法通过构造函数的参数显式地暴露依赖关系,因此在IntelliSense中很容易看到依赖关系.

  2. 维护问题(让我感到困惑)
    请考虑以下示例

我们有一个使用服务定位器方法的类'MyType':

public class MyType
{
    public void MyMethod()
    {
        var dep1 = Locator.Resolve<IDep1>();
        dep1.DoSomething();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我们要为类'MyType'添加另一个依赖项

public class MyType
{
    public void MyMethod()
    {
        var dep1 = Locator.Resolve<IDep1>();
        dep1.DoSomething();

        // new dependency
        var dep2 = Locator.Resolve<IDep2>();
        dep2.DoSomething();
    }
}
Run Code Online (Sandbox Code Playgroud)

这就是我的误解开始的地方.作者说:

要判断你是否引入了一个重大改变,要变得更加困难.您需要了解使用Service Locator的整个应用程序,并且编译器不会帮助您.

但是等一下,如果我们使用DI方法,我们将在构造函数中引入与另一个参数的依赖关系(在构造函数注入的情况下).问题仍然存在.如果我们忘记设置ServiceLocator,那么我们可能忘记在IoC容器中添加新的映射,并且DI方法将具有相同的运行时问题.

此外,作者还提到了单元测试的难点.但是,我们不会有DI方法的问题吗?我们不需要更新所有实例化该类的测试吗?我们将更新它们以传递一个新的模拟依赖项,以使我们的测试可编译.我没有看到更新和时间花费带来任何好处.

我不是想捍卫Service Locator方法.但这种误解让我觉得我失去了一些非常重要的东西.有人可以消除我的怀疑吗?

更新(摘要):

我的问题"服务定位器是反模式"的答案实际上取决于具体情况.我绝对不会建议你从工具列表中删除它.当您开始处理遗留代码时,它可能会变得非常方便.如果你很幸运能够处于项目的最初阶段,那么DI方法可能是更好的选择,因为它比Service Locator有一些优势.

以下是主要的不同之处,这些差异使我不相信我的新项目使用Service Locator:

  • 最明显和最重要的是:Service Locator隐藏了类依赖项
  • 如果你正在使用一些IoC容器,它可能会在启动时扫描所有构造函数以验证所有依赖项,并立即给你关于缺失映射(或错误配置)的反馈; 如果您将IoC容器用作服务定位器,则无法进行此操作

有关详细信息,请阅读下面给出的优秀答案.

design-patterns dependency-injection anti-patterns service-locator

127
推荐指数
4
解决办法
3万
查看次数

Mark Seemann关于Bastard Injection的相互矛盾的陈述.需要一些澄清

我正在阅读他的书" 网上依赖注入".

1)他在这里Bastard Injection只有在我们使用时才会发生Foreign Default.

但在他的书中,第148页上的插图显示,Bastard Injection当依赖项的默认实现是Foreign Default或者Local Default:

在此输入图像描述

那么当依赖的默认实现是一个时,Bastard Injection反模式也会出现Local Default吗?

2)在这里(以及他的书中)他指出,如果一个类有一个可选的依赖,那么这个依赖的默认实现是好的Local Default:

但在下一篇文章中,他似乎反对拥有可选的依赖项,即使默认实现Local Default:

private readonly ILog log;
public MyConsumer(ILog log)
{
    this.log = log ??LogManager.GetLogger("My");
}
Run Code Online (Sandbox Code Playgroud)

就封装而言,这种方法的主要问题在于,看起来MyConsumer类无论是否控制其日志依赖的创建都无法真正决定.虽然这是一个简化的示例,但如果LogManager返回的ILog实例包装了一个非托管资源,这可能会成为问题,该资源应该在不再需要时处理掉.

当依赖的默认实现是本地的时,他在上面的摘录中的参数是否也有效?如果是这样,那么还应该避免使用具有本地默认值的可选依赖项?

3)Pg.147:

Bastard Injection的主要问题是它使用了FOREIGN DEFAULT ...,我们不能再自由地重用该类了,因为它拖拽了我们可能不想要的依赖.进行并行开发也变得更加困难,因为类很大程度上依赖于它的依赖性.

Foreign Default是一个依赖项的实现,它被用作默认值,并在与其使用者不同的程序集中定义.因此,对于Foreign Default,使用者的程序集也会依赖于依赖项的程序集.

他是否也暗示Foreign Default使并行开发更加困难,而Local Default则不然?如果他是,那么这没有意义,因为我认为使并行开发变得困难的原因并不是消费者的集合很难引用依赖的汇编,而是消费者阶层依赖于一个具体实现的事实.依赖?

谢谢

dependency-injection

22
推荐指数
1
解决办法
1442
查看次数

ASP.NET 5/ASP.NET Core 1中关注点和n层架构的分离

由于我想使用新的内置依赖注入,我很难找到一种优雅的方法来保持我的DAL层与ASP.NET 5中的MVC/UI层分开.

例如,我有一个ASP.NET 5项目,一个业务层项目和一个数据访问项目,其中我有各种实体框架代码,如实体和上下文.在ASP.NET 5中设置上下文并定位数据库主要文档建议我在StartUp.cs类中执行类似的操作

services.AddEntityFramework()
    .AddSqlServer()
    .AddDbContext<BookContext>(options =>
    {
        options.UseSqlServer(Configuration.Get("Data:ConnectionString"));
    });
Run Code Online (Sandbox Code Playgroud)

这意味着我现在必须在基本上我的UI层中引用我的DAL,根据各种专家和博客文章,多年来一直是不好的做法.

我解决这个问题的一种方法是创建两个新项目,一个是CompositeRoot项目,它包含工厂类来生成我的业务类然后访问DAL,还有一个带有Configuration类的Utilities项目,其中有一个ConnectionString属性,我可以传入我的上下文,然后我使用内置的DI来连接所有内容并避免在我的UI层中引用我的DAL.但我遇到了最新版本的Entity Framework(beta 7)的问题,因为它现在似乎无法在上下文的构造函数或可重写中指定连接字符串OnConfiguration方法.此外,到目前为止,所有文档似乎都不关心这种混合问题.这就是我们现在做事的方式吗?相信开发人员不会做直接在UI中引用DAL类的"坏"事情?或者是否有一种模式,人们正在使用这种新的内置DI /配置为ASP.NET 5保持SOLID?

asp.net dependency-injection entity-framework-core asp.net-core-mvc asp.net-core

21
推荐指数
2
解决办法
4306
查看次数

如何使用Simple Injector模拟模块/安装程序/注册表

Autofac有模块,Windsor有安装程序和StructureMap注册表...使用Simple Injector如何将配置逻辑打包成可重用的类?

我试过了:

public interface IModule { }

public class FooModule : IModule
{
    public FooModule(SimpleInjector.Container container)
    {
        container.RegisterSingleton<IBar, Bar>();
        container.RegisterSingleton<IFoo, Foo>();
    }
}
Run Code Online (Sandbox Code Playgroud)

我在Composition Root中使用它:

public static void Main(string[] args)
{
    var container = new SimpleInjector.Container();
    container.RegisterCollection<IModule>(new FooModule(container));
    ...
}
Run Code Online (Sandbox Code Playgroud)

但是,FooModule取决于容器,可能不是一个好的做法...请参阅http://code.google.com/p/autofac/wiki/BestPractices:

如果组件依赖于容器,请查看它们如何使用容器来检索服务,并将这些服务添加到组件(依赖注入)构造函数参数中.

.net c# dependency-injection ioc-container simple-injector

13
推荐指数
1
解决办法
3854
查看次数

清洁架构澄清

我一直在从鲍勃叔叔那里读到这篇文章:

http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html 在此输入图像描述

我有几个问题需要澄清:

  1. 外圈可以指向内部跨越多个边界.例如,控制器可以访问实体中的数据结构吗?
  2. 企业业务规则与应用程序业务规则之间有何区别.例如stackoverflow之类的区别是什么?stackoverflow的应用程序业务规则和企业业务规则是什么?
  3. 是否有我可以参考的示例代码,主要关注Web应用程序.

谢谢

architecture oop

13
推荐指数
2
解决办法
2283
查看次数

Xml配置还是通过代码配置?

我个人喜欢从C#代码配置StructureMap的选项.根据我的理解,DI的优点之一是我们可以轻松交换新的具体实例.但是,如果配置是在代码中定义的,那么具体实例在dll中是硬编码的.

所以,实际上,它与硬件编码依赖关系一样好,对吧?我知道,在测试过程中它会让生活更轻松......

我的观点是,使用xml配置不是更好吗?你想插入一个新的具体实例?只需让安装程序用新的文件覆盖structuremap.config文件.

那么,配置StructureMap的首选方法是什么?

额外:我暂时被迫使用C#配置,因为我不知道如何将连接字符串传递给实例.我可以在配置文件中编写连接字符串,但我想重用app.config中定义的连接字符串.

structuremap dependency-injection inversion-of-control

10
推荐指数
2
解决办法
2535
查看次数

如何防止c#类中的构造函数滥用

我一直在尝试在asp.net MVC5应用程序中实现一个松散耦合的应用程序.我有一个控制器:

public class HeaderController : Controller
    {
        private IMenuService _menuService;

        public HeaderController(IMenuService menuService)
        {
            this._menuService = menuService;
        }

        //
        // GET: /Header/
        public ActionResult Index()
        {

            return View();
        }


        public ActionResult GetMenu()
        {

            MenuItem menu = this._menuService.GetMenu();
            return View("Menu", menu);

        }

    }
Run Code Online (Sandbox Code Playgroud)

此控制器中使用的服务是:

public class MenuService : IMenuService
{
    private IMenuRespository _menuRepository;

    public MenuService(IMenuRespository menuRepository)
    {
        this._menuRepository = menuRepository;
    }

    public MenuItem GetMenu()
    {
        return this._menuRepository.GetMenu();
    }
}
Run Code Online (Sandbox Code Playgroud)

并且在服务类中使用的存储库是:

public class MenuRepository : IMenuRespository
    {
        public MenuItem GetMenu()
        { …
Run Code Online (Sandbox Code Playgroud)

c# asp.net asp.net-mvc dependency-injection inversion-of-control

10
推荐指数
1
解决办法
688
查看次数

使用具有依赖注入的策略和工厂模式

我正在开展一个侧面项目,以更好地理解控制和依赖注入的反转以及不同的设计模式.

我想知道在工厂和战略模式中使用DI是否有最佳实践

我的挑战来自于一个策略(从工厂构建)需要为每个可能的构造函数和实现提供不同的参数.结果,我发现自己在服务入口点声明了所有可能的接口,并将它们传递给应用程序.因此,必须针对新的和各种策略类实现更改入口点.

为了便于说明,我在下面汇总了一个配对示例.我的这个项目的堆栈是.NET 4.5/C#和Unity for IoC/DI.

在此示例应用程序中,我添加了一个默认的Program类,负责接受虚构的订单,并根据订单属性和所选的送货提供商计算运费.UPS,DHL和Fedex有不同的计算方法,每个实现可能依赖或不依赖于其他服务(访问数据库,api等).

public class Order
{
    public string ShippingMethod { get; set; }
    public int OrderTotal { get; set; }
    public int OrderWeight { get; set; }
    public int OrderZipCode { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

用于计算运费的虚拟计划或服务

public class Program
{
    // register the interfaces with DI container in a separate config class (Unity in this case)
    private readonly IShippingStrategyFactory _shippingStrategyFactory;

    public Program(IShippingStrategyFactory shippingStrategyFactory)
    {
        _shippingStrategyFactory = shippingStrategyFactory;
    }

    public …
Run Code Online (Sandbox Code Playgroud)

c# design-patterns dependency-injection strategy-pattern factory-pattern

10
推荐指数
3
解决办法
1万
查看次数

autofac解析所有类型的开放泛型类型?

我猜测没有办法像Autofac那样做以下内容,为ctor注入一个可枚举的开放泛型类型集合?各种Handle类型都有依赖关系,否则我只是动态构建它们.

    class EventOne : IEvent {...}
    class EventTwo : IEvent {...}
    class EventThree : IEvent {...}
    interface IHandleEvent<T> where T : IEvent {...}
    class HandleEventOne : IHandleEvent<EventOne> {...}
    class HandleEventTwo : IHandleEvent<EventTwo> {...}
    class HandleEventThree : IHandleEvent<EventThree> {...}

    builder.RegisterAssemblyTypes(myAssembies).AsClosedTypesOf(typeof(IHandleEvent<>));
    builder.RegisterType<AService>().As<IAService>();


    class AService : IAService
    {
      public AService(IEnumerable<IHandleEvent<IEvent>> handles)
      {...}
    }
Run Code Online (Sandbox Code Playgroud)

c# autofac

9
推荐指数
1
解决办法
3117
查看次数