2016-07-05 81 views
4

我想了解DI,有一个更好的了解国际奥委会,以及其他好处。依赖注入和项目引用

预DI,我有一个具有UI项目(MVC),一个BusinessLogic项目和数据访问项目的项目。我也有一个SharedLib项目。所有项目都有对SharedLib的引用。 UI具有对BusinessLogic的引用,并且BusinessLogic具有对DataAccess的引用。

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

但为了注入DataAccess类,我在UI项目的BusinessLogic类中实例化,我需要一个对Data项目的引用,因为UI项目(正确地说,我认为)不知道' IDataAccess'界面。我能看到的唯一解决方法是在我的UI项目中添加项目引用到我的DA项目中 - 这看起来不对。

如果我尝试添加团结作为我的容器(有一天,在未来,一旦我的工作如何,所有的作品),并希望我的初始化界面/用户界面中的项目类关系 - 同样的问题。

也许接口必须在某些共享的项目去了?还是一个项目了?这应如何处理?

+0

项目引用(例如循环引用)和DI是两个单独的顾虑。添加引用可能不一定是件坏事。正确的答案取决于DI使用的是什么工具。我建议你调查一下你喜欢的任何DI工具,并根据你的需求评估它的功能集。 –

+0

为了详细阐述我上面所说的内容;在许多DI工具中,你必须在某个地方连接哪些服务已注册到哪些接口。一旦注册,您就不会自己手动创建实例。当您正确使用DI时,您的UI将不会创建您的业务对象的实例,它将被注入到您的UI控制器的构造函数中,就像将DataAccess注入到业务逻辑类中一样。例如。花更多时间了解DI工具的运行方式,尤其是MVC应用程序,因为它们是一种特殊的生物。 –

+0

您也可以将您的类放入其所属的程序集内部,并仅将接口公开。像Autofac这样的DI容器可以连接程序集中的所有类,并仅通过它们的接口使它们可用。 –

回答

4

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

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

数据层

业务层不再需要提供一个IDataAccessFactory你的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(); 
    } 
} 

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

+0

好贴!我正在尝试通过它。谢谢。 – Craig