【问题标题】:Inject different implementations into same interface then pick up right implementation in right project / assembly将不同的实现注入同一个接口,然后在正确的项目/程序集中选择正确的实现
【发布时间】:2015-09-10 02:59:34
【问题描述】:

我们有 2 个OpenLdap 服务器。一个是最新的开箱即用版本。另一个是较旧的高度定制版本。

两种实现都遵循类似的逻辑。以连接为例。

界面如下

namespace Infrastructure.Interfaces
{
    public interface ISessionService
    {
        LdapConnection GetConnection();       
    }
}

每个实现都将使用此接口来获取连接。

新服务器

namespace Infrastructure.NewLdap.Service
{
    public class SessionService : ISessionService
    {
        LdapConnection GetConnection()
        {
        .....
        }
    }
}

旧服务器

namespace Infrastructure.OldLdap.Service
{
    public class SessionService : ISessionService
    {
        LdapConnection GetConnection()
        {
        .....
        }
    }
}

每个实现都在不同的项目中。每个项目都会有一个不同的app.config 以及正确的凭据等。除此之外,还有一个IConfigService,它会将所有凭据等从app.config 加载到其中。

namespace Infrastructure.Interfaces
{
    public interface IConfigService
    {
        string ServerAddress { get; }   
        ...   
        ...   
    }
}

同样,每个项目都有自己的实现。

每个项目中的存储库会有所不同,因为我们在每个服务器中访问数据的方式不同。旧服务器将仅用于查询,因此我们使用它将用户导入新服务器。

我将如何使用Simple Injector 将这些服务注入同一个接口,但根据使用的存储库,将引入正确的实现?有道理吗?

  • Infrastructure.OldLdap.SomeRepo 使用Interfaces.ISessionService 注册OldLdap.Service.SessionService
  • Infrastructure.NewLdap.SomeOtherRepo使用Interfaces.ISessionService注册NewLdap.Service.SessionService

这是否可能,这是否也破坏了Liskov Substitution Principle

我最好把每个实现都写成自己的东西吗?如果是这样,这会不会违反DRY 原则?

希望这不是太笼统,提前谢谢您。

【问题讨论】:

    标签: c# ioc-container dry simple-injector solid-principles


    【解决方案1】:

    这也违反了 Liskov 替换原则。

    是否破坏 LSP 取决于 SessionService 类的行为方式。你应该经常问自己:“如果我交换实现会发生什么?”如果将Oldldap 注入NewRepo 导致NewRepo 在运行时失败,则您违反了LSP,这基本上是在告诉您您的设计是错误的。另一方面,如果NewRepo 保持正常运行,因为OldldapNewldap 在合同上的行为相同,那你就没事了。存储库是否关心它的实现,还是只有你关心。请注意,如果OldldapNewRepo 执行速度太慢,则可能不违反 LSP。在这种情况下,只有您关心(或者可能是您的客户,因为非功能性要求)。

    解决 LSP 违规的方法总是很简单:为每个实现提供自己的接口。开发人员往往会遇到这个问题,因为这两个抽象似乎彼此完全重复,并且制作“副本”似乎违反了 DRY。但是外表是骗人的;虽然他们有相同的成员,但他们有不同的、不兼容的合同。

    但是,如果您没有违反 LSP,则保留该单一接口就可以了(根据 LSP)。您可以使用 RegisterConditional 使用 Simple Injector 3 进行多个上下文注册,如下所示:

    container.RegisterConditional<ISessionService,
        Infrastructure.OldLdap.Service.SessionService>(
        c => c.Consumer.ImplementationType.Namespace.Contains("Oldldap"));
    
    container.RegisterConditional<ISessionService,
        Infrastructure.NewLdap.Service.SessionService>(
        c => c.Consumer.ImplementationType.Namespace.Contains("Newldap"));
    

    【讨论】:

    • 如果连接的详细信息正确,会话服务将始终返回连接。该功能仅负责建立连接。感谢您的详细解答
    猜你喜欢
    • 1970-01-01
    • 2020-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-13
    • 1970-01-01
    相关资源
    最近更新 更多