如果你不想让你可以看看工厂/抽象工厂项目之间的引用。
你的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
项目引用(例如循环引用)和DI是两个单独的顾虑。添加引用可能不一定是件坏事。正确的答案取决于DI使用的是什么工具。我建议你调查一下你喜欢的任何DI工具,并根据你的需求评估它的功能集。 –
为了详细阐述我上面所说的内容;在许多DI工具中,你必须在某个地方连接哪些服务已注册到哪些接口。一旦注册,您就不会自己手动创建实例。当您正确使用DI时,您的UI将不会创建您的业务对象的实例,它将被注入到您的UI控制器的构造函数中,就像将DataAccess注入到业务逻辑类中一样。例如。花更多时间了解DI工具的运行方式,尤其是MVC应用程序,因为它们是一种特殊的生物。 –
您也可以将您的类放入其所属的程序集内部,并仅将接口公开。像Autofac这样的DI容器可以连接程序集中的所有类,并仅通过它们的接口使它们可用。 –