之前一直不理解IOC DI,今天使勁研究了下,感覺朦朦朧朧有點感覺了,網上的這篇文章對我的有很大的啟發
http://www.cnblogs.com/jin-yuan/p/3823559.html
我仔細學習了后,按照自己的習慣從頭到尾自己敲了個實例,最后能跑起來了,感覺特高興,除了用來理解IOC和DI思想,基本沒考慮其他,但是還是貼出來記錄下吧
1,我們先實現一個簡單的讀取數據庫的功能,由於懶得真的去讀數據庫了,直接模擬了,首先是一個簡單的實體類User
namespace ConsoleApp1 { public class User { public int UserID { get; set; } public string UserName { get; set; } } }
2,然后模擬一個空的DBHelper,只是用來感受IOC的方便,沒有真正實現效果,因為要依賴抽象,所以下面的類基本每個都定義了一個接口
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp1 {
public interface IDBHelper {
int Execute(string sql);
}
/// <summary>
/// 模擬的DBHelper
/// </summary>
public class DBHelper : IDBHelper {
private ILogHelper logHelper;
public DBHelper(ILogHelper logHelper) {
this.logHelper = logHelper;
}
public int Execute(string sql) {
logHelper.Info("執行sql:" + sql);
return 1;
}
}
}
3,DBHelper里面有個LogHelper只是一個輸出類,模擬工具類,也是為了體驗DI的便利性
using System;
namespace ConsoleApp1 {
public interface ILogHelper {
void Info(string msg);
}
public class LogHelper : ILogHelper {
public void Info(string msg) {
Console.WriteLine("info: " + msg);
}
}
}
4,然后是模擬的數據訪問類,里面用集合模擬數據庫
using System.Collections.Generic;
namespace ConsoleApp1 {
public interface IUserDAL {
int Add(User user);
List<User> GetUsers();
}
public class UserDAL : IUserDAL {
private IDBHelper dbHelper;
public UserDAL(IDBHelper dbHelper) {
this.dbHelper = dbHelper;
}
public static List<User> users = new List<User>() {
new User(){
UserID = 1,
UserName ="張三"
},
new User(){
UserID =2,
UserName ="李四"
}
};
public int Add(User user) {
dbHelper.Execute("insert into User (UserID,UserName) values (3,'王五')");
users.Add(user);
return 1;
}
public List<User> GetUsers() {
return users;
}
}
}
5,然后是業務邏輯類,在里面調用數據訪問類,以及工具類,如果是傳統的寫法,這里就要都new一下,既不美觀又很繁瑣
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp1 {
public interface IUserBLL {
int Add(User user);
List<User> GetUsers();
}
public class UserBLL : IUserBLL {
private IUserDAL userDAL;
private ILogHelper logHelper;
public UserBLL(IUserDAL userDAL, ILogHelper logHelper) {
this.userDAL = userDAL;
this.logHelper = logHelper;
}
public int Add(User user) {
logHelper.Info("UserBLL.Add");
return userDAL.Add(user);
}
public List<User> GetUsers() {
logHelper.Info("UserBLL.GetUsers");
return userDAL.GetUsers();
}
}
}
6,模擬是實現的DI管理類,為了好理解,我按照最簡單的方式實現的,大佬的例子這里也會考慮IOC,所以比我這復雜一些
using System;
using System.Collections.Generic;
using System.Reflection;
namespace ConsoleApp1 {
/// <summary>
/// 簡單模擬的DI注入類
/// </summary>
public class DIManager {
/// <summary>
/// 存放關系的容器
/// </summary>
private Dictionary<Type, Type> container;
public DIManager() {
container = new Dictionary<Type, Type>();
}
/// <summary>
/// 將接口和實現類關聯綁定起來
/// </summary>
public void Bind<K, V>() {
container.Add(typeof(K), typeof(V));
}
/// <summary>
/// 獲取泛型類型的對象
/// </summary>
public T Get<T>() {
return (T)Injection(typeof(T));
}
/// <summary>
/// 對傳入的類型進行構造函數注入
/// </summary>
private object Injection(Type type) {
object instance = null;
foreach (ConstructorInfo ci in type.GetConstructors()) { //循環類的構造函數
if (ci.GetParameters().Length > 0) {
List<object> parameters = new List<object>();
foreach (ParameterInfo pi in ci.GetParameters()) { //循環構造函數的參數
if (container.ContainsKey(pi.ParameterType)) {
parameters.Add(Injection(container[pi.ParameterType])); //遞歸實現所有相關注冊過的類型的構造函數注入
}
}
instance = CreateInstance(type, parameters.ToArray());
break;
}
}
if (instance == null) {
instance = CreateInstance(type);
}
return instance;
}
/// <summary>
/// 創建對象
/// </summary>
private object CreateInstance(Type type, params object[] args) {
return Activator.CreateInstance(type, args);
}
}
}
7,最后是Program的使用,我們只要在程序運行的時候,注冊綁定需要用到的抽象和實現,然后就能直接通過Get獲取實例,並且這些實例中的構造函數都會自動創建注入相關的對象,這樣就不用我們各種重復的new了
using System;
namespace ConsoleApp1 {
class Program {
static void Main(string[] args) {
DIManager manager = new DIManager();
manager.Bind<IUserBLL, UserBLL>();
manager.Bind<IUserDAL, UserDAL>();
manager.Bind<IDBHelper, DBHelper>();
manager.Bind<ILogHelper, LogHelper>();
IUserBLL userBLL = manager.Get<UserBLL>();
User user = new User() { UserID = 3, UserName = "王五" };
Console.WriteLine(userBLL.Add(user));
foreach (var u in userBLL.GetUsers()) {
Console.WriteLine(u.UserName);
}
Console.ReadKey();
}
}
}
總結:IOC是控制反轉,就是把底層的耦合拋到外面,類的內部只依賴抽象,代碼里定義的那么多接口就是實現這個效果,但是即使我們把控制拋到了外面,這些對象還是得創建啊,所以就用到了DI(依賴注入)上面的類里面都是通過構造函數來獲取我們要用到得對象,我們依賴這些對象,對象哪來的?答,注冊接口和類得關系,然后在代碼里自動生成的,你可以觀察DIManager的Injection,大致就是根據類的類型獲取構造函數信息,創建構造函數的參數類型的對象,然后根據構造函數以及參數對象創建本身的對象來達到注入的效果,最后遞歸注入所有相關的構造函數(這里貌似性能浪費啊,假如我只使用UserBLL的一個方法,而這個方法有咩有真正的使用UserDAL和LogHelper,那么程序就創建了白創建了2個用不到的對象,不知道真正的DI是不是解決了這個問題呢)
依然是朦朦朧朧,繼續研究!
