依赖注入和项目引用

时间:2016-07-05 00:56:11

标签: c# 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项目中初始化我的接口/类关系 - 同样的问题。

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

1 个答案:

答案 0 :(得分:4)

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

您的UI了解您的业务层,因此您希望在业务层中定义知道如何使用数据层的工厂。然后在合成根中处理所有DI(本例中的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<IDataAccessFactory, XmlDataAccessFactory>();

    var logic = container.Resolve<BusinessLogic>();
    logic.DoSomethingWithData();

    string useDataInUI = logic.GetSomeData();
    Console.WriteLine("UI " + useDataInUI);

    Console.ReadKey();
}

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

e.g。您可能在数据层数据库,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();
    }
}

数据层

您的业务层不再需要为您的用户界面提供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<IPlatformFactory, WebPlatformFactory>();

    var logic = container.Resolve<BusinessLogic>();
    logic.DoSomethingWithData();

    string useDataInUI = logic.GetSomeData();
    Console.WriteLine("UI " + useDataInUI);

    Console.ReadKey();
}

UI然后对数据层/访问一无所知,只是将工厂创建交给业务层,业务层保存数据(和定价)参考。

一些推荐阅读:

Composition Root

Implementing an Abstract Factory

Compose object graphs with confidence