用Delphi控件来理解C#的接口和依赖注入
Delphi 最让开发者喜欢的地方就是组件可视化。拖拽组件,关联一下组件,不用代码就搞定好多组件(类)关联上的东西,不同类之间互相引用,传递数据的实现。
拖出几个组件,配置一下组件之间的引用关联。
修改Connection组件里要连接的数据库类型。
以上操作,都是Delphier非常习以为常的事情,没感觉有什么大不了。增删改查询可以直接使用DBGrid上组件内置的功能都能直接实现。
要切换mssql oracle sqlite pg,在Connection组件里面换一下DriverId就行了。
但是,对于C#来说,刚开始学习的时候通常例子都是这样的。
DAL:
public class DALMsSqlHelper { Connection = 'mssql=DB=IP=PWD='; public int add(Data data) { // 省略具体实现 return 1; } public int edit(Data data) { // 省略具体实现 return 1; } public int del(Data data) { // 省略具体实现 return 1; } }
BLL:
public class BLLStudent { DALMsSqlHelper mssql = null; public BLLStudent() //构造函数 { //DAL层 mssql = new DALMsSqlHelper(); } public int addStudent(Data data) { //...省略具体实现 return mssql.add(data); } public int editStudent(Data data) { //...省略具体实现 return mssql.edit(data); } public int delStudent(Data data) { //...省略具体实现 return mssql.del(data); } }
UI:
public class UI { BLLStudent std = new BLLStudent(); public UI() { std.addStudent(data); std.editStudent(data); std.delStudent(data); } }
应该说简单得不能在简单的三层。
如果要换Oracel数据库呢?那要修改代码才行。
DAL:
public class DALOracleSqlHelper { Connection = 'oracel=DB=IP=PWD='; public int add(Data data) { // 省略具体实现 return 1; } public int edit(Data data) { // 省略具体实现 return 1; } public int del(Data data) { // 省略具体实现 return 1; } }
显然BLL也要进行修改,因为BLL引用了DAL的查询类。
BLL:
public class BLLStudent { DALOracleSqlHelper orasql = null; public BLLAddStudent() //构造函数 { //Orcale数据库 DAL层 orasql = new DALOracleSqlHelper(); } public int addStudent(Data data) { // 省略具体实现 return orasql.add(str); } public int editStudent(Data data) { // 省略具体实现 return orasql.edit(str); } public int delStudent(Data data) { // 省略具体实现 return orasql.del(str); } }
UI:不变。
不就换个oracle数据库吗?为何修改这么大,要是哪天又要换回mssql怎么办?
首先,我们定义一个数据访问的接口。
public interface ISqlHelper { int add(); int edit(); int del(); }
DAL修改如下:
public class DALMsSqlHelper : ISqlHelper { public int add(Data data) { // 省略具体实现 return 1; } // 省略具体实现,如修改 删除 查询 } public class DALOracleSqlHelper : ISqlHelper { public int add(Data data) { // 省略具体实现 return 1; } // 省略具体实现,如修改 删除 查询 }
BLL修改如下:
public class BLLAddStudent { ISqlHelper sqlHelper = null; public BLLAddStudent(ISqlHelper sqlhelper) { this.sqlHelper = sqlhelper; } public int addStudent(Data data) { return sqlHelper.add(data); } //省略具体实现,修改,删除,查询 }
UI修改如下:
public class UI { public UI() { //创建Helper接口对象 ISqlHelper sqlhelper = new DALOracleSqlHelper(); BLLStudent std = new BLLStudent(sqlhelper); std.addStudent(data); } }
如果哪天又要换会mssql怎样办。那么仅仅只要修改UI 创建Helper接口对象为 DALMsSqlHelper
public class UI { public UI() { ISqlHelper sqlhelper = new DALMsSqlHelper(); //修改Helper接口对象 BLLStudent std = new BLLStudent(sqlhelper); std.addStudent(data); } }
如果又换数据库,修改为连接MySql呢?
首先需要重新写个mysql的实现。
DAL:
public class DALMySqlHelper : ISqlHelper
{
public int add(Data data)
{
// 省略具体实现
return 1;
}
// 省略具体实现,如修改 删除 查询
}
UI实现如下:
public class UI
{
public UI()
{
ISqlHelper sqlhelper = new DALMySqlHelper();
BLLStudent std = new BLLStudent(sqlhelper);
std.addStudent(str);
}
}
有没有发现。我们只是在DAL新增了一个mysql的实现和修改了下UI层的接口构造。其中BLL我们根本就没有动它的。
是的,这样我们就可以说这里的UI对于BLL来说就是”依赖注入“,BLL对于UI来说就是”控制反转“。所以,我觉得依赖注入和控制反转是同一个概念,只是立场不同。
上面,我们看到了虽然BLL层已经不需要变动就可以新增一个数据源的访问。那么我们能不能也不修改UI层呢?
这里就可以用到反射了。
然后,不管想怎么折腾,我只需要改改配置文件就可以了。甚至都不用动代码。(如果需要新增一个数据源操作,也只要重新实现下,然后改改配置文件)。