dependency injection和项目引用

我正在尝试了解DI,以便更好地了解IoC以及其他好处。

Pre DI,我有一个项目,它有一个UI项目(MVC),一个BusinessLogic项目和一个DataAccess项目。 我也有一个SharedLib项目。 所有项目都引用了SharedLib。 UI引用了BusinessLogic,BusinessLogic引用了DataAccess。

我想现在添加接口。 所以我转到我的DataAccess,并为每个类添加一个接口,并用他们的方法填充它们。 我对业务逻辑层也这样做。

但是为了注入我在UI项目中的BusinessLogic类中实例化的DataAccess类,我需要对我的Data项目的引用,因为UI项目(正确地,我认为)不知道’IDataAccess’接口是什么。 我能看到的唯一解决方法是在我的UI中将项目引用添加到我的DA项目中 – 这似乎是错误的。

如果我尝试添加Unity作为我的容器(将来的一天,一旦我弄清楚这一切是如何工作的),并希望在UI项目中初始化我的接口/类关系 – 同样的问题。

也许接口必须进入某个共享项目? 还是一个项目? 应如何处理?

如果您不希望项目之间的引用,您可以查看工厂/抽象工厂。

您的UI了解您的业务层,因此您希望在业务层中定义一个知道如何使用数据层的工厂。 然后在合成根中处理所有DI(本例中的UI项目)。

下面使用控制台应用程序作为UI的一个简单示例,坚持您在问题中陈述的参考

数据层

public interface IDataAccess { string GetData(); } public class XmlDataAccess : IDataAccess { public string GetData() { return "some data"; } } 

业务层

 public interface IDataAccessFactory { IDataAccess GetDataAccess(); } public class XmlDataAccessFactory : IDataAccessFactory { public IDataAccess GetDataAccess() { return new XmlDataAccess(); } } public class BusinessLogic { IDataAccessFactory dataAccessFactory; public BusinessLogic(IDataAccessFactory dataAccessFactory) { this.dataAccessFactory = dataAccessFactory; } public void DoSomethingWithData() { IDataAccess dataAccess = dataAccessFactory.GetDataAccess(); Console.WriteLine(dataAccess.GetData()); } public string GetSomeData() { IDataAccess dataAccess = dataAccessFactory.GetDataAccess(); return dataAccess.GetData(); } } 

UI

 static void Main(string[] args) { IUnityContainer container = new UnityContainer(); container.RegisterType(); var logic = container.Resolve(); logic.DoSomethingWithData(); string useDataInUI = logic.GetSomeData(); Console.WriteLine("UI " + useDataInUI); Console.ReadKey(); } 

这是一个人为的例子,所以它看起来像什么都没有抽象,但有一个现实世界的例子,它会更有意义。

例如,您可能在数据层数据库,xml文件等中有许多不同的数据访问类,因此您可以为业务层中的每个类定义一个工厂。


使用抽象工厂

工厂可以包含更多关于数据层细节的逻辑,或者作为抽象工厂向业务逻辑层提供一组单独的工厂。

业务层

您可能会在业务层中拥有一个抽象工厂,例如

 public interface IPlatformFactory { IDataAccessFactory GetDataAccessFactory(); IPricingFactory GetPricingFactory(); // might be in the business project, or another project referenced by it } 

与一个混凝土工厂

 public class WebPlatformFactory : IPlatformFactory { IDataAccessFactory GetDataAccessFactory() { return new XmlDataAccessFactory(); } IPricingFactory GetPricingFactory() { return new WebPricingFactory(); // not shown in the example } } 

(您可能有其他具体工厂,如RetailPlatformFactory等)

您的BusinessLogic类现在看起来像

 public class BusinessLogic { IPlatformFactory platformFactory; public BusinessLogic(IPlatformFactory platformFactory) { this.platformFactory = platformFactory; } public void DoSomethingWithData() { IDataAccessFactory dataAccessFactory = platformFactory.GetDataAccessFactory(); IDataAccess dataAccess = dataAccessFactory.GetDataAccess(); Console.WriteLine(dataAccess.GetData()); } public string GetSomeData() { IDataAccessFactory dataAccessFactory = platformFactory.GetDataAccessFactory(); IDataAccess dataAccess = dataAccessFactory.GetDataAccess(); return dataAccess.GetData(); } } 

数据层

您的业​​务层不再需要为您的UI提供IDataAccessFactory ,因此您可以在此示例中将其移动到数据层中。 所以数据层类就是

 public interface IDataAccess { string GetData(); } public class XmlDataAccess : IDataAccess { public string GetData() { return "some data"; } } public interface IDataAccessFactory { IDataAccess GetDataAccess(); } public class XmlDataAccessFactory : IDataAccessFactory { public IDataAccess GetDataAccess() { return new XmlDataAccess(); } } 

UI

现在,您将在UI中配置容器并执行类似的操作

 static void Main(string[] args) { IUnityContainer container = new UnityContainer(); container.RegisterType(); var logic = container.Resolve(); logic.DoSomethingWithData(); string useDataInUI = logic.GetSomeData(); Console.WriteLine("UI " + useDataInUI); Console.ReadKey(); } 

用户界面然后对数据层/访问一无所知,它只是将工厂创建交给业务层,业务层保存数据(和定价)引用。

一些推荐阅读:

组成根

实现抽象工厂

自信地构建对象图