依赖倒置原则(DIP)、控制反转(IoC)、依赖注入(DI)(C#)
象的控制權交由配置文件控制,然后根據配置文件中的信息(程序集+類型),通過反射來獲取對象,而不是直接new對象,這也是控制反轉的一種體現。
IoC容器會連接程序中的所有模塊,模塊將所需對象的控制權都交由IoC容器控制,IoC容器會根據用戶配置的信息將各個模塊所需要的對象事先創建完成,然后IoC容器可以通過依賴注入(DI)的方式為模塊注入所需對象(還有依賴查找(DL)),依賴注入就是一種具體實現的手段。
依賴倒置原則、控制反轉和依賴注入并不是為程序帶來新的功能,而是使得程序中模塊的耦合性降低,提高每個模塊的復用性。
舉個栗子:
就拿生活中最常見的自助取款機來說一下,首先我們要擁有一張銀行卡,例如建設銀行的銀行卡CCBCard類(設計的一些屬性可能不太合理,不過重要的是了解思想)
//建行銀行卡public class CCBCard
{
//銀行卡中的錢
public decimal Money { get; set; }
//銀行卡名字
public String Name { get; set; }
public CCBCard(decimal money,String name)
{
this.Money = money;
this.Name = name;
}
}
然后我們來創建一個ATM自動取款機類,該取款機擁有取錢和存錢的功能
ATM機1.0
//自動取款機public class ATM
{
//建行銀行卡
public CCBCard Card = new CCBCard(1000,"建行卡");
//取錢
public void SubMoney(decimal money)
{
//判斷余額是否足夠
if (Card.Money >= money)
{
//取錢
this.Card.Money -= money;
Console.WriteLine($"取錢成功,余額{Card.Money}");
}
else {
Console.WriteLine("余額不足");
}
}
//存錢
public void AddMoney(decimal money)
{
//存錢
this.Card.Money += money;
}
}
因為這個例子是生活中非常常見的,所以大家肯定一眼就看出了不妥
此時的ATM機可是說是個非常“睿智”的ATM機了,我去取錢,而ATM機卻自帶了一張建行銀行卡,與其說是個ATM機,倒不如說只能對一個CCBCard建行卡進行存取的機器。此時ATM類完全依賴于CCBCard對象,而且CCBCard對象也是由ATM類創建的,如果CCBCard修改了,或者要換其他的卡,ATM機還要做出修改。
所以接下來我們應該將這不好的兩點改掉:
1、ATM機只能讀取單一的CCBCard卡(ATM控制CCBCard對象的創建)
2、ATM只能讀取CCBCard類型的卡(ATM完全依賴于CCBCard對象)
先來解決第一點,接下來我們改進一下,為ATM機增加構造函數,通過構造函數傳遞CCBCard對象,使得ATM機可以操作其他建行卡:
ATM機2.1:
增加構造函數,兩個方法不用變
//建行銀行卡public CCBCard Card;
//構造函數傳入CCBCard對象
public ATM(CCBCard card)
{
this.Card = card;
}
使用:
//銀行卡CCBCard card = new CCBCard(1000,"建行卡");
//ATM
ATM atm = new ATM(card);
//取錢
atm.SubMoney(100);
?然后來解決第二個問題,只能存取建行卡:
此時就需要用到依賴倒置原則,讓ATM類依賴于CCBCard抽象,而不是具體的實現。如果我們想存取其他銀行卡里面的錢,必須為所有的銀行卡抽象出一個接口,然后讓所有銀行卡子類都實現這個接口。
//銀行卡接口public interface ICard
{
string Name { get; set; }
decimal Money { get; set; }
}
建行卡實現該接口:
//建行銀行卡public class CCBCard:ICard
{
//銀行卡中的錢
public decimal Money { get; set; }
//銀行卡名字
public String Name { get; set; }
public CCBCard(decimal money,String name)
{
this.Money = money;
this.Name = name;
}
}
使得ATM機依賴于ICard接口(修改了Card屬性和構造函數),而且ATM機并不控制ICard的子類,而是將控制權交由調用者。這一切才合情合理啊,無論用戶插入什么卡,該ATM機都能進行存取。這就是控制反轉,而通過構造函數傳入的ICard對象則是通過依賴注入的方式注入對象。
//建行銀行卡public ICard Card;
//構造函數傳入ICard對象(依賴注入)
public ATM(ICard card)
{
this.Card = card;
}
依賴注入還有其他兩種:通過接口和屬性注入
//屬性注入public ICard Card { get; set; }//接口注入
//該方法實現了接口
public void Inject(ICard card)
{
this.Card = card;
}
而接口注入就是通過方法注入,此種方式會增加不必要的接口,現在基本不使用,大多為構造函數注入。
新添加一個ICBC(工商銀行)卡進行測試
//工商銀行卡public class ICBCCard : ICard
{
public string Name { get; set; }
public decimal Money { get; set; }
}
測試:
//建設銀行卡CCBCard bcard = new CCBCard(1000, "CCB");
//工商銀行卡
ICBCCard ccard = new ICBCCard()
{
Money = 1000,
Name = "ICBC"
};
//ATM
ATM atm1 = new ATM(bcard);
ATM atm2 = new ATM(ccard);
//取錢
atm1.SubMoney(100);
IoC容器就是專門為ATM機這種模塊服務的,它就像是一個大齒輪一樣,連接所有小齒輪(模塊),它運轉,整個程序便運轉,如果有些模塊可能需要用到其他模塊中的對象,它們并不會直接依賴,而是全都由IoC容器控制。
雖然互相需要,但是互不依賴,IoC容器會事先將ICard子類創建好,然后通過依賴注入注入到ATM機中(Unity、Spring.NET等框架都是封裝完善的IoC容器),ATM機只管接收,只管索取。ATM機是不對子類進行創建的,控制權在用戶手里,由用戶控制ATM機操作何種銀行卡,就像你去取錢一樣,你插入什么卡自助取款機都可以取錢,這看起來是多么平常的一件事?很多看起來高大上的思想,都是從需求演變過來的,然后由前人一點點探索研究總結出來。
至此ATM機已經完成了,可能因為ATM機太常見了,所以我所說的一切你都可以想到(換卡,換不同銀行的銀行卡),就像是在說廢話,如果你都理解了,那么根據ATM機,你應該仔細的思索一下,你所設計的類和模塊滿不滿足像ATM機一樣的“功能”?
原文鏈接:https://www.cnblogs.com/ckka/p/11448065.html
.NET社區新聞,深度好文,歡迎訪問公眾號文章匯總?http://www.csharpkit.com?
總結
以上是生活随笔為你收集整理的依赖倒置原则(DIP)、控制反转(IoC)、依赖注入(DI)(C#)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 做“是非题”的正确姿势
- 下一篇: 四种为HttpClient添加默认请求报