代码之家  ›  专栏  ›  技术社区  ›  Xaqron

如何将依赖项注入实现接口的类中?

  •  6
  • Xaqron  · 技术社区  · 14 年前

    5 回复  |  直到 14 年前
        1
  •  7
  •   Merlyn Morgan-Graham    14 年前

    我知道你说过你想要一份稳定的合同。但对 提供一个稳定的接口是,您的依赖项可能会随不同的实现而大幅度变化,这将减少耦合:

    public interface IBlogRepository
    {
        IEnumerable<Entry> GetEntries(int pageId, int pageCount);
    }
    
    class BlogDatabase : IBlogRepository
    {
        public BlogDatabase(ISession session)
        {
            this.session = session;
        }
    
        public IEnumerable<Entry> GetEntries(int pageId, int pageCount)
        {
            // Not that you should implement your queries this way...
            var query = session.CreateQuery("from BlogEntry");
            return query.Skip(pageId * pageCount).Take(pageCount);
        }
    
        private ISession session;
    }
    

    正如您所说,您还可以将依赖项实现为属性(或参数),但这将硬编码您的依赖项,而不是使它们特定于实现。您将分离您的特定会话实现,但仍然必须依赖于会话。

    public interface IBlogRepository
    {
        ISession Session { get; set; }
        IEnumerable<Entry> GetEntries(int pageId, int pageCount);
        IEnumerable<Entry> GetEntriesWithSession(ISession session,
            int pageId, int pageCount);
    }
    
    class BlogDatabase : IBlogRepository
    {
        public ISession Session { Get; set; }
    
        public IEnumerable<Entry> GetEntries(int pageId, int pageCount)
        {
            var query = Session.CreateQuery ...
        }
    
        public IEnumerable<Entry> GetEntries(ISession session, int pageId, int pageCount)
        {
            var query = session.CreateQuery ...
        }
    }
    
    class BlogFile : IBlogRepository
    {
        // ISession has to abstract a file handle.  We're still okay
        // ...
    }
    
    class BlogInMemory : IBlogRepository
    {
        // ISession abstracts nothing.
        // Maybe a lock, at best, but the abstraction is still breaking down
        // ...
    }
    

    我相信这三个都是公认的做法。至少有两个流行的框架同时支持构造函数和属性注入。

    这意味着决定权在你,什么对你的项目最有意义。取舍是一个易于跟踪的依赖关系图,而不是更强的耦合。当然,决策也不一定是所有构造函数或所有属性/参数。

    另一个需要考虑的高级抽象是抽象工厂类。如果要对一组依赖项进行分组,或者需要在运行时构造它们的实例,则可以执行此操作:

    public interface IInstallationFactory
    {
        IUser CreateRegisteredUser(Guid userSid);
        IPackage CreateKnownPackage(Guid id);
        IInstaller CreateInstaller();
    }
    

        2
  •  3
  •   davisoa    14 年前

    一个选项是在接口上创建初始化方法。此方法可以接受所有必需的依赖项。

    类似于:

    void Configure(dependency1 value, etc.);
    

    斯科特·汉斯曼有一个很好的名单 here .

        3
  •  2
  •   Carlo V. Dango    14 年前

    你需要做的是让你所有的接口实现子类化一个类,其中一个构造函数接受任何需要注入的状态。由于子类需要在其构造函数中执行基调用,因此您的约束将自动维护。

    起初,这可能看起来是一个奇怪的模式,但是我们在企业解决方案中一直使用它,所以我保证它是正确的:-)

        4
  •  0
  •   Xaqron    14 年前

    set-only 属性,则对象负责保存对传递给它的内容的引用:

    public interface IBlogRepository
    {
        ISession Session { set; }
    }
    
    class BlogRepository : IBlogRepository
    {
       private ISession m_session;
    
       ISession Session
       {
          set { m_session = value; }
       }
    }
    

    仅设置 属性是依赖项注入,因为 仅设置 good practice 或者不是,但对我来说,从现在开始。

        5
  •  0
  •   Stefan    7 年前

    可能有一个实现使用数据库,另一个实现使用文件系统来保存数据。

    接口应该声明哪些依赖项是必需的?数据库管理器还是文件系统管理器?

    推荐文章