依赖关系注入和项目引用

本文关键字:项目 引用 注入 关系 依赖 | 更新日期: 2023-09-27 17:55:13

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

在DI之前,我有一个项目,它有一个UI项目(MVC),一个BusinessLogic项目和一个DataAccess项目。我还有一个SharedLib项目。所有项目都有对SharedLib的引用。UI 引用了 BusinessLogic,BusinessLogic 引用了 DataAccess。

我现在想添加接口。因此,我转到我的 DataAccess,为每个类添加一个接口,并用它们的方法填充它们。我对业务逻辑层执行相同的操作。

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

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

也许接口必须放在某个共享项目中?还是一个项目?应该如何处理?

依赖关系注入和项目引用

如果你不想要项目之间的引用,你可以看看工厂/抽象工厂。

您的 UI 知道您的业务层,因此您希望在业务层中定义一个知道如何使用数据层的工厂。然后,处理合成根(此示例中的 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();
    }
}

用户界面

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();
}

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

例如,数据层数据库中可能有一堆不同的数据访问类、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 中配置容器并执行类似的操作

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 对数据层/访问一无所知,它只是将工厂创建移交给业务层,业务层保存数据(和定价)引用。

一些推荐阅读:

组成根

实现抽象工厂

自信地编写对象图