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(); }
用户界面然后对数据层/访问一无所知,它只是将工厂创建交给业务层,业务层保存数据(和定价)引用。
一些推荐阅读:
组成根
实现抽象工厂
自信地构建对象图