JAVA中使用接口实现松耦合

松耦合就是降低系统部件和部件之间的耦合性,也就是降低部件的依赖性,使得部件之间相对独立,这样对于日后系统的维护及扩展都是很有好处的,然而在J2EE领域,为实现松耦合出现的技术可谓让人眼花缭乱,这些技术的出现究竟是使问题简单化了还是复杂化了呢?
首先是数据工厂技术,这种技术使用到了传统的接口的使用方式,而且有一套它自己的做法,然而却因为在使用过程中需要写通过工厂类来取句柄的代码而受争议,于是又出现了Ioc模式,这种在容器或框架上大作文章的做法是好还是坏呢?(既然是框架就应该是个架子,架子需要骨头不需要肉)。
下面我对使用接口去实现松耦合讲一下自己的做法,仅供参考,欢迎大家参与讨论,共同提高。
在计算机硬件里,不同的硬件之间就是靠接口(Interface)来进行衔接的,我们有了一块图形显示卡(Graphic Interface)之后,就可以不停地更换显示器了。然而JAVA中为什么会使用到接口(Interface)这一名词呢,“参照硬件的做法去实现衔接”我想就是JAVA定义接口的最初目的,但是对于如何去具体应用接口或用好接口,JAVA语言的开发者似乎没有给出太多的描述,这就给后者对接口的使用留下了很大的发挥余地和想象空间,于是才有了各种各样的接口使用方法(如数据工厂).
部件的衔接是为了部件的交互,软件系统中部件之间的交互大体上可以分为数据的交互和代码的交互。无论是C、C++还是JAVA里,static存储类型都有着相同的含义,那就是相同类的不同句柄之间在内存中的共享部分,这个共享的部分可以是数据,也可以是代码,我们可以随时地改变这些静态类型的东西,只是在定义这些东西时需要给它初始化而已。这样我们可以把static用到JAVA的接口里来实现数据的共享。然而JAVA对接口的使用却给出了重重的限制,如在接口中不能定义static类型的方法,或者虽然可以定义static类型的属性,但却只能是常量,而不能是变量。但我们可以想办法去绕过这些障碍,例如我使用了HashSet或Collection作为接口中的静态属性,在使用中并没有用到“=”号去改变它们,而却用到了它们的add或remove方法去改变它们,这样在编译时就侥幸地绕过了“JAVA中不允许改变接口里的静态属性”这一检查机制,编译和运行都通过了,并获得了想要的结果。
下面给出这些测试情况:
测试一:实现部件之间数据的交互,写了三个java文件,分别为Interface.java、ClassA.java和ClassB.java。
--------------------------------------------------------------------------------------
import java.util.HashSet;

public interface Interface{
public static HashSet testPro = new HashSet(); //所有实现此接口的类的共享属性
}

--------------------------------------------------------------------------------------
public class ClassB implements Interface{

}
--------------------------------------------------------------------------------------
import java.util.*;

public class ClassA implements Interface{

public static void main(String[] argv){
String str1 = "test1";
ClassB.testPro.add(str1); //ClassB想往外传送数据,便把数据赋给共享属性

//在ClassA中通过共享属性拿到了ClassB想传出的数据
for(Iterator iterator = ClassA.testPro.iterator();iterator.hasNext();){
String tempStr = (String)iterator.next();
System.out.println(tempStr);
}
}
}
--------------------------------------------------------------------------------------
编译、运行都通过,输出:test1 ,结果正确,实现了ClassA和ClassB之间的数据的交互


测试二:实现部件之间代码的交互,同样是这三个JAVA文件。
--------------------------------------------------------------------------------------

import java.util.HashSet;

public interface Interface{
public static ClassA instanceA = new ClassA(); //所有实现此接口的类的共享属性
public static ClassB instanceB = new ClassB(); //所有实现此接口的类的共享属性
}
--------------------------------------------------------------------------------------

public class ClassB implements Interface{

public void method(){
System.out.println("B.method invoked!");
}

}
--------------------------------------------------------------------------------------

public class ClassA implements Interface{

public static void main(String[] argv){
instanceB.method(); //在ClassA中直接可以拿ClassB的句柄来用,因为此句柄是接口里的共享属性
}

}
---------------------------------------------------------------------------------------
测试通过,输出: B.method invoked! ,实现了ClassA和ClassB中代码的交互


这种做法不会给系统添加任何乱七八糟的技术或东西,保持系统的清新、整洁。今后我们要维护或扩展系统的时候,根据需要重新开发或改变某些接口就可以了。


你这两个代码中,都存在统一的紧偶合问题:

Class A依赖于ClassB,ClassB万一发生变化,甚至ClassB名称变为ClassC了,那么你就必须更改ClassA代码,这就不是松偶合了。

你可能会想到:在Class A中,使用Interface来替代ClassB,那么带来另外一个问题,ClassB实例何时注射到Interface实现中?这就需要Ioc/DI了

你的思维中好像是接口是不能改是的,接口给出来就是让你改的,ClassB有任何变动的话在接口中改就可以了

在ClassA中仅仅是引用到了ClassB的共享的句柄而已,甚至连ClassB的类名都没有涉及到,如果你是说在ClassA中的main方法中出现了ClassB的类名那我可真的是无语了

"ClassB实例何时注射到Interface实现中?这就需要Ioc/DI了"------你的思维太僵化了,别把"注射"这词看得那么"高尚",这东西根本就不是好东西。J2EE那帮佬大部分都有个一个通用的毛病:那就是好像只要能实现就行,其它的全都不会去考虑。编程这东西,只要锁定一个目标,哪怕中途是兜兜转转,总是能达到目的地的,或者得出一个“不能实现”这一结论,但是回想一下中间那些兜兜转转的路程究竟值不值得呢?就像1+1可以等于2,但1+2-1也一样可以等于2,这就是为什么他们弄出来的东西可取的占50%,不可取的也占50%。
但也不怪他们,因为那帮佬根本就是一群伪君子,打着“开源”的口号走“商业”的道路,或许他们的技术真的是有问题,或许他们觉得弄出来的东西越复杂,对于他们“赚钱”越有利。登陆一下SPRING那帮佬的英文网站去看看吧,看他们是靠什么去赚钱的,他们根本就不需要出售他们的SPRING去赚钱,何况出售的话也不一定可以赚到钱,因为这种东西难于说服别人去买,于是便借着“开源”的口号乘机扩大SPRING的影响力,然后通过“广告效应”大搞培训大赚它一笔,他们每搞一次培训每一天就能赚它个几百万,这还需要出售他们的那东西吗?看看他们在网上登的广告吧,真是越看越让人觉得恶心!

运行时再去修改代码、组织代码,这种技术虽然很奥妙,而且在某些时候可能确实可以派上用场,但这却是一种很笨的做法,只有到万不得已时才好考虑这么做,因为这样做会使问题复杂化而且可能会影响到性能,但JAVA那帮佬却把它作为主流技术来推捧,还好现在的CPU有3G,要是过去的133MHZ的那可就完啦。但无论这东西现在对性能的影响明不明显都好,这种做法都是不可取的,因为1+1可以等于2,但他们却用了1+2-1才等于2,大大地把问题搞复杂化了,要是系统再稍微复杂一点的话,那就是复杂+复杂,等于“超级复杂”。

>,如果你是说在ClassA中的main方法中出现了ClassB的类名那我可真的是无语了

你应该无语,我说的就是这个意思,你好好理解对象关系中“依赖”定义,ClassA对ClassB产生了依赖。

正是Ioc/DI出现在你现有思维视野之外,所以你才有那么多牢骚啊,呵呵。

>运行时再去修改代码、组织代码,这种技术虽然很奥妙,而且在某些时候可能确实可以派上用场,但这却是一种很笨的做法,只有到万不得已时才好考虑这么做,因为这样做会使问题复杂化而且可能会影响到性能,但JAVA那帮佬却把它作为主流技术来推捧

你这段话很有道理,现在硬件设备低廉和快速的基础上,设计成了压倒一切的目标,离需求现场越近,软件修改成本就越低,最理想是:运行现场配置一下,系统的新需求实现就完成,当发现现场工具家伙不够时,来个基于互联网的SOA,这下十八般武艺全部可以搬到软件运行现场了。

>,你应该无语,我说的就是这个意思,你好好理解对象关系中“依赖”定义,ClassA对ClassB产生了依赖


彭大哥呀,我main方法只是写来测试用的,完全可以去掉的,真怀疑你对代码的理解能力。

另外,你的十八般武艺还是想想办法看可不可以用到别的地方吧,踩死一只蚂蚁不需要用到十八般武艺。

移植其他地方都是一样,依赖跟着走,总是为客户端。

我之前语气可能不太好,请谅解,不过,我还是觉得,如果了解了GoF模式,对于调用和被调用关系就有了深刻理解。