一、简介
1、IOC核心理论来源DIP
DIP全称是Dependence Inversion Principle,中文叫依赖倒置原则。这是面向对象程序设计六大原则之一。
它的原则讲的是面向对象语言程序设计时,高层模块不要直接依赖于低层模块,二者应该通过抽象来依赖而不是依赖于细节。依赖细节,会导致低层的变化影响高层。依赖抽象, 低层的变化就不会影响高层,保持稳定,可扩展。对扩展开放,对修改封闭!这就是IOC的核心理论根基。
2、为什么依赖细节会导致底层的变化影响高层呢?
拿我们的三层架构来说,如下图,IOCTest是控制台程序,引用Dal和Bll层,Bll引用Dal层。
program.cs代码如下
UserSqlServerDal userDal = new UserSqlServerDal(); UserBll userBll = new UserBll(userDal); userBll.Login(1);
userBll的代码如下
public class UserBll { private UserSqlServerDal UserSqlServerDal { get; set; } public UserBll(UserSqlServerDal userSqlServerDal) { UserSqlServerDal= userSqlServerDal; } public bool Login(int id) { object obj= UserSqlServerDal.Find(id); return true; } }
UserSqlServerDal的代码如下
public class UserSqlServerDal { public object Find(int id) { return null; } }
如上代码,bll层引用了dal层的细节,console引用了bll的 细节。什么时候会造成下层的改动会引起上层的变更呢?
当我想切换数据库的时候,比如不用现在的sqlserver了,想换成mysql。那么这个时候就必须新增一个UserMysqlDal的dal类。然后bll层和console层的UserSqlServerDal都需要换成UserMysqlDal类。
public class UserBll { // private UserSqlServerDal UserSqlServerDal { get; set; } // public UserBll(UserSqlServerDal userSqlServerDal) // { // UserSqlServerDal= userSqlServerDal; // } //public bool Login(int id) //{ // object obj = UserSqlServerDal.Find(id); // return true; //} private UserMySqlDal UserMySqlDal { get; set; } public UserBll(UserMySqlDal userMySqlDal) { UserMySqlDal = userMySqlDal; } public bool Login(int id) { object obj= UserMySqlDal.Find(id); return true; } }
//UserSqlServerDal userDal = new UserSqlServerDal(); UserMySqlDal userDal = new UserMySqlDal(); UserBll userBll = new UserBll(userDal); userBll.Login(1);
那如果需要兼容oracle,sqlLite等其他数据库的话,那bll和ui层不是要写一堆相同作用的代码?可以看的出来这种代码后期维护起来可真要命。所以不能依赖细节,而应该依赖抽象。下面我们对bll层和dal层进行解耦,使它们之间依赖抽象。新建一个Dal的接口层,让所有的具体Dal类继承这个接口。删除bll对dal的依赖引用。
namespace Test.IDal { public interface IUserDal { object Find(int id); } }
public class UserMySqlDal:IUserDal public class UserSqlServerDal:IUserDal
public class UserBll { private IUserDal UserDal { get; set; } public UserBll(IUserDal userDal) { UserDal = userDal; } public bool Login(int id) { object obj= UserDal.Find(id); return true; } }
IUserDal userDal = new UserMySqlDal(); UserBll userBll = new UserBll(userDal); userBll.Login(1);
这样,不管你ui层的userDal是mysql的实例还是sqlserver的实例,bll层都以统一的抽象来接受,下次更换mongodb的dal就不再需要修改userBll的代码了。
上面的ui层中,是不是还有new UserMysqlDal()和new UserBll的细节依赖,可以看到ui层都是在做实例化吧,这些实例化的过程就可以统一交给一个模块来做这个事情。
新建一个IBll层用来解耦UI和BLL层。
新建一个Common层来放Factory类专门来实现实例化类,引用IBLL,BLL,IDAL,DAL四个项目。
public class Factory { public static IUserDal CreateDal() { return new UserMySqlDal(); } public static IUserBll CreateBll(IUserDal dal) { return new UserBll(dal); } }
删除UI层对BLL和DAL项目的引用。修改相关代码
IUserDal userDal = Factory.CreateDal(); IUserBll userBll = Factory.CreateBll(userDal); userBll.Login(1);
这样就让UI,BLL,DAL都依赖于抽象了。好处显然易见,只需要修改factory这个第三方库,就能完成数据库的切换了。改中间层的花销要比改上下层的风险要低得多。