反向控制(IoC)
由于此次是初探我就先来扯扯IoC理论的无关的东西,英文全称:Inversion of Control (控制反转),它的另一个名称:依赖注入,DI 全称;Dependency Injection。
IoC的产生:我先来列举一个普通的例子来说明为甚么会用IoC,(至于为什么尚未考究) 我们一般存储数据会有以下方式:向数据库中存储数据,向文本文件中存储数据,向xml中存储数据,编写这类程序我们一般是编一个具体的存储位置类,有各自的存储位置实现自己的存储方式,这显然听起来合情合理,那我们就来实现以下它.
//******Database.java**************
public class Database{
public void savaDB(){ }
}
当应用程序需要存储数据时通过Database.java中的方法来向数据库存储数据
//*******Business.java**************
public class Business{
private Database db = new Database();
public void savaData(){
db.savaDB();
}
}
可是现在又要存储数据了,不过这次要存到文本里,上面的那个Business就不适用了,得稍加改动
//******TXTdata.java*******************
public class TXTdata{
public savaTXT(){ }
}
/*******Business.java**************
public class Business{
private TXTdata db = new TXTdata();
public void savaData(){
db.savaTXT();
}
}
同样,当要向XML中存储数据时Business又得重新修改。如果我们在设计应用程序时这样来进行代码设计,估计现在随便一个小软件都比现在win8操作系统的代码还长,bug就更不敢说了。
很明显在设计中,我们对Business这个类进行了重复编码,而出现重复编码就说明我们对类的抽象没做好。再来看看Business这个类,我们希望在这个类里面实现保存数据这个功能,但我们不关心保存数据的方式(只要能够正确保存),再看看我们前面的设计将保存方式编码进来,很明显就是我们想多了(好心办坏事了)。而对Business
类里的保存数据我们去掉它的具体方式时,则以上几个Business就一样了,重复编码就没有了,这个问题完美解决了。另外两个问题又来了,1,具体的保存方式该置于何地 2,Business如何知道怎样保存?(牵一发而动全身呀)。不过,当我们看出第一个问题时,这个问题就已经被我们解决了,在java中,对于几个类的方法我们如何将其统一起来,很明显这就是泛化,处理泛化方法的办法就不用说了,我们定义一个SavaData的接口里面实现一个savaData的方法,然后让Database,TXTdata,XMLdata继承这个接口,在实现接口方法时实现其各自的存储方式,到此第一个问题就解决了。再来看第二个问题:首先可以肯定是通过把接口SaveData传给类Business来实现数据的保存,可是将接口传过来得有个接收者来保存一下,因此Business里应该有个SaveData的接口属性,由于这个属性值会发生改变,因此我们给它提供一个set方法,至此就剩下Business类里的saveData方法该如何设计了,很明显SavaData(注意区别SaveData与saveData)属性已经有了,只需根据继承该属性的对象调用其saveData方法即可。两个问题都解决了,我们来看一下代码实现:
//**********SavaData.java***********************
public interface SaveData{
public void saveData(){ }
}
//******Database.java**************
public class Database implement SaveData{
public void savaData(){
//具体负责向数据库保存数据的代码
}
}
//******TXTData.java**************
public class TXTData implement SaveData{
public void savaData(){
//具体负责向文本文件保存数据的代码
}
}
//*******Business.java**************
public class Business{
private SaveData db ;
public void setSaveData( SaveData db ){ this.db = db; }
public void savaData(){ db.savaData(); }
}
IoC 的大致意思基本上说完了,下面写个test实验一下:
//*******test.java**************
public class test{
Business bs = new Business();
//根据注入的存储类来存储数据
public void saveData(){
bs.setSaveData(new Daatabase());
bs.saveData();
}
}
通过上面的示例解释,面向接口编程的好处那就不用说了,至于为何叫“反向控制”,我们再来探讨一番,反向控制其意思是说:原来由业务逻辑来控制具体的存储方式,即业务逻辑编写具体的存储方式,面向接口后,不在业务逻辑里编写具体的存储方式了,而是在调用业务的类里控制具体的存储方式,好像是由具体的存储方式来控制业务逻辑了,所以叫“反向控制”(写这些话太不爽了, )。由于这个名字不好理解,所以改了一个好理解一点的“依赖注入”,(本人觉得不看上面的代码,这个名字更难理解")上面举例是“依赖注入"的一种方式,即通过set的方式进行注入,它还有两种注入方式分别是:接口注入,构造注入。
前面已经对注入的原理机制讲明白,后两种大同小异,只是实现方式略有差异,因此只写一下它的实现代码。
接口注入:
编写一个接口, 各种存储方式的注入都将通过这个接口进行。
public interface Businness{
public void IsaveData(SaveData db);
}
public class BusinessImpl implement Business{
private SaveData db;
public void IsaveData(SaveData db){
this.db = db;
}
public void saveData(){
db.saveData();
}
}
构造注入:
在接受注入的类中定义一个构造方法,并在参数中定义需要注入的类。
//*******Business.java**************
public class Business{
private SaveData db ;
public Business( SaveData db ){ this.db = db; }
public void savaData(){ db.savaData(); }
}
至此,只是简单的探究了一下IoC的实现机制,至于spring框架中的详细实现细节,仍在学习中..............
ps: C# 静态构造函数 (目测于下周三完成)