如果你不想讓你可以看看工廠/抽象工廠項目之間的引用。
你的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容器可以連接程序集中的所有類,並僅通過它們的接口使它們可用。 –