關於依賴注入的一些理解
在EF Core中預設實現了DI容器,這樣就不需要類似Ninjet這樣的元件來幫助我們完成容器配置。
首先,為什麼需要使用依賴注入
基本回答就是鬆耦合,減少依賴。
我們先加入一個業務場景,定義一個實現CRUD的介面,又定義了一個類來實現介面,那我們在Main函式中想呼叫CRUD的方法,
需要new一個例項,類似這樣的Interface name = new class()。
我們需要的是,在一個類的內部不通過建立物件的例項而獲得了某個實現公開介面物件額引用。這種需要就稱為DI(依賴注入,Dependency Injection)
在面向物件中有一個OCP原則,即開放關閉原則,指設計應該對擴充套件開放,對修改關閉。在程式實際中利用多型性,隔離變化。才會使的程式具有健壯性,而不是臃腫。
依賴注入的正式定義:
依賴注入(Dependency Injection),是一個過程:由於某客戶類只依賴於服務類的一個介面,而不依賴於具體服務類,所以客戶類只定義一個注入點。在程式執行過程中,客戶類不直接例項化具體服務類例項,而是客戶類的執行上下文環境或專門元件負責例項化服務類,然後將其注入到客戶類中,保證客戶類的正常執行。
依賴注入有三種實現方式,建構函式注入,方法注入以及屬性注入。
在EF Core中都可以在使用任何一種,完成依賴注入,
在Artech大佬的部落格中可以檢視具體的注入方式和效果,寫下這篇部落格也是加深自己瞭解,為什麼需要這樣做,這樣做的好處是什麼樣。
從笨程式碼開始,學習新的方式才會體會這樣做的好出。
提出一個較小例子的程式碼。
介面類
using System; using System.Collections.Generic; using System.Text; namespace ConsoleApp6 { internal interface IAttackStrategy { void AttackTarget(Monster monster); } internal sealed class WoodSword : IAttackStrategy { public void AttackTarget(Monster monster) { monster.Notify(20); } } internal sealed class IronSword : IAttackStrategy { public void AttackTarget(Monster monster) { monster.Notify(50); } } internal sealed class MagicSword : IAttackStrategy { private Random _random = new Random(); public void AttackTarget(Monster monster) { Int32 loss = (_random.NextDouble() < 0.5) ? 100 : 200; if (200 == loss) { Console.WriteLine("出現暴擊!!!"); } monster.Notify(loss); } } }
怪物類
using System; using System.Collections.Generic; using System.Text; namespace ConsoleApp6 { /// <summary> /// 怪物 /// </summary> internal sealed class Monster { /// <summary> /// 怪物的名字 /// </summary> public String Name { get; set; } /// <summary> /// 怪物的生命值 /// </summary> private Int32 HP { get; set; } public Monster(String name, Int32 hp) { this.Name = name; this.HP = hp; } /// <summary> /// 怪物被攻擊時,被呼叫的方法,用來處理被攻擊後的狀態更改 /// </summary> /// <param name="loss">此次攻擊損失的HP</param> public void Notify(Int32 loss) { if (this.HP <= 0) { Console.WriteLine("此怪物已死"); return; } this.HP -= loss; if (this.HP <= 0) { Console.WriteLine("怪物" + this.Name + "被打死"); } else { Console.WriteLine("怪物" + this.Name + "損失" + loss + "HP"); } } } }
角色類
using System; using System.Collections.Generic; using System.Text; namespace ConsoleApp6 { /// <summary> /// 角色 /// </summary> internal sealed class Role { /// <summary> /// 表示角色目前所持武器 /// </summary> public IAttackStrategy Weapon { get; set; } /// <summary> /// 攻擊怪物 /// </summary> /// <param name="monster">被攻擊的怪物</param> public void Attack(Monster monster) { this.Weapon.AttackTarget(monster); } } }
主函式類
using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace ConsoleApp6 { class Program { static void Main(string[] args) { //生成怪物 Monster monster1 = new Monster("小怪A", 50); Monster monster2 = new Monster("小怪B", 50); Monster monster3 = new Monster("關主", 200); Monster monster4 = new Monster("最終Boss", 1000); //生成角色 Role role = new Role(); //木劍攻擊 role.Weapon = new WoodSword(); role.Attack(monster1); //鐵劍攻擊 role.Weapon = new IronSword(); role.Attack(monster2); role.Attack(monster3); //魔劍攻擊 role.Weapon = new MagicSword(); role.Attack(monster3); role.Attack(monster4); role.Attack(monster4); role.Attack(monster4); role.Attack(monster4); role.Attack(monster4); Console.ReadLine(); } } }
輸出結果
臨時想到了,利用反射也可以達成這種效果,反射也是實現依賴注入的一種方式。
使用反射+工廠模式,利用Assembly.Load(DependencyLocate
).CreateInstance(
"DependencyLocate."
+ Type
),DependencyLocate是實現介面的程式集位置,Type是代表程式集下具體的位置(一般為具體類名)